Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# interface Doesn't allow member class to forfill requirements

Tags:

c#

interface

Sorry if the title is not very descriptive. I didn't know how to describe this.

First, I created an interface like this:

public interface IUser {}

Then implemented it in several classes like this:

public class Student : IUser {}

public class Teacher : IUser {}

Then I created an Interface that required the first interface

public class IUsers
{
    List<IUser> Users {get; set;}
}

Then I created a Class that used the second interface, but used one of the Members of the first interface to for fill the contract.

public class Students : IUsers 
{
    List<Student> Users {get; set;}
}

The problem is the last one I wanted to constrain the list to just one implementation of the interface, but still need to maintain the interface for data compatibility. When I do this I get an error saying I'm not implementing the interface. I thought that since Student implemented the interface it would for fill the obligation, but it doesn't seem to. Is this correct or am I doing something else wrong

like image 715
evilsushi Avatar asked Dec 20 '25 17:12

evilsushi


2 Answers

You need to say what kind of users your collection supports. Suppose your code were valid - then this would compile:

IUsers users = new Students();
// What would this do at execution time? It's not safe!
users.Users.Add(new Teacher());

After all, that's just adding a Teacher to a List<IUser>, right? But in Students, the Users property is a List<Student>, so that can't accept a teacher.

The best approach is probably to make your IUsers interface generic in the type of user it accepts:

public class IUsers<TUser> where TUser : IUser
{
    List<TUser> Users {get; set;}
}

Then your Students class would implement IUsers<Student>, and the property would be fine.

At that point, the problematic example at the top of the answer would fail to compile:

// This is fine
IUsers<Student> users = new Students();
// This won't compile, because users.Users is of type List<Student>, and you can't add
// a Teacher to that.
users.Users.Add(new Teacher());
like image 159
Jon Skeet Avatar answered Dec 23 '25 07:12

Jon Skeet


Based on the code, to me the sample appears to indicate you would like to maintain separate implementations for your users, then return the desired implementation.

public interface IStudentFactory
{
     IUser Create();
}

public class StudentFactory
{
    public IUser Create() => new StudentContext();
}

Then based on your implementation inside your interface of IUser, you could connect to your data store to manage those types of user.

var context = new StudentFactory().Create())
var students = context.GetAllStudents();
context.Students.Add(new Student() { }); 

The approach I provided is under the notion that you want to be able to access this information about different types of users, persist, and manage. Your example showed a primitive collection where you are adding, potentially handling other functionality, but I imagine you are working more towards something a bit more consistent.

I may be off the mark for your intent, but that is how I interpreted.

like image 38
Greg Avatar answered Dec 23 '25 05:12

Greg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!