1

I had wrote this codes:

public interface IUser
{
   string Username { get; set; }
   string Password { get; set; }
   IList<IRole> Roles { get; set; }
}

public interface IRole
{
   string Name { get; set; }
   IList<IUser> Users { get; set; }
}

public class User : IUser
{
   public string Username { get; set; }
   public string Password { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public IList<Role> Roles { get; set; }
}

public class Role : IRole
{
   public string Name { get; set; }
   public IList<User> Users { get; set; }
}

I think in logic there is no problem. Because User class is type of IUser interface, and Role class is type of IRole interface too. But it doesn't compile. Actually Compiler doesn't recognize that classes are type of their interfaces. The question is why is this happening and what to do?

1
  • Role does not implement interface member IRole.Users. Users cannot implement IRole.Users because it does not have the matching return type of IList<IRole>. Commented Mar 13, 2015 at 19:24

4 Answers 4

3

Consider this, you have:

public interface IRole
{
   string Name { get; set; }
   IList<IUser> Users { get; set; }
}

And then you have:

public class Role : IRole<User>
{
   public string Name { get; set; }
   public IList<User> Users { get; set; }
}

Now imagine I added:

public class SomeOtherUser : IUser
{ 
   //...
}

I could do this (ignoring for a moment the uninitialized list):

var role = new Role();
var iRole = (IRole)role;
iRole.Users.Add(new SomeOtherUser());

But that should not, and cannot work. Because SomeOtherUser isn't a User. They both implement IUser, but you definition in the Role class of the Users property is IList<User> not IList<IUser>.

So you have to change Role to implement the interface you gave it:

public class Role : IRole<User>
{
   public string Name { get; set; }
   public IList<IUser> Users { get; set; }
}

And you'll have to cast the elements in Users when you use them if you need extra properties that are part of User but not IUser. Or you could create another property to provide direct access to the underlying IList<User>, but the you'll might need to cast your IRole to a Role. Or if you can edit the the interface, using generics as @ChrFin suggested is a great solution.

Sign up to request clarification or add additional context in comments.

Comments

3

Interface must match exactly and you hace a mismatch on properties Roles and Users

On Role, you have to replace this

public IList<User> Users { get; set; }

by this

public IList<IUser> Users { get; set; }

And something similar for User. Replace this

public IList<Role> Roles { get; set; }

by this

public IList<IRole> Roles { get; set; }

4 Comments

Yes, it solve the problem in this situataion, But doesn't solve my problem. Because User class have more properties than its' interface, and I need that properties.
Your code won't work as you already realized, you may need to define a new interface matching your requirements.
@m.ghadiri: You can't do that. The interface says it's a IList<IUser>, but your class says it's. a much more specific. IList<User>. If I get your class, cast it to the interface IRole and then try and add an instance of a different class that implements IUser to Users, what do you think is going to happen?
I wrote that interfaces in a library and import its dll to my project. And my classes are in different place from the library.
2

If you want to use the specific types you could use generics:

public interface IUser
{
   string Username { get; set; }
   string Password { get; set; }
}
public interface IUser<TRole> : IUser where TRole : IRole
{  
   IList<TRole> Roles { get; set; }
}

public interface IRole
{
   string Name { get; set; }
}
public interface IRole<TUser> : IRole where TUser : IUser
{
   IList<TUser> Users { get; set; }
}

public class User : IUser<Role>
{
   public string Username { get; set; }
   public string Password { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public IList<Role> Roles { get; set; }
}

public class Role : IRole<User>
{
   public string Name { get; set; }
   public IList<User> Users { get; set; }
}

5 Comments

Is there a purpose to defining both generic and non-generic IUser and IRole interfaces? The classes only implement the generic ones.
@CoderDennis: Yes: If you do not need the list in some places you can just use IUser instead of IUser<TRole> which can be usefull if you do not know the type of TRole there...
In your example, User isn't an IUser and Role isn't an IRole, so your generic constraints won't pass.
@CoderDennis: I just wanted to write "Of course they are. User implements IUser<Role> and IUser<TRole> extends IUser => User is also an instance of IUser because of that inheritence." and then I saw that I forgot to define exactly that inheritance -> thanks, fixed...
I wish I could upvote this again. It really is a great answer.
1

Ignoring the typo of class as mentioned by a commenter, your classes do not implement the interfaces completely, specifically in Role, you need:

public IList<IUser> Users { get; set; }

Rather than:

public IList<User> Users { get; set; }

Similarly, in the class User you need:

public IList<IRole> Roles { get; set; }

instead of:

public IList<Role> Roles { get; set; }

2 Comments

I had mentioned my special situation in comment of Claudio Redi's asnwer. My code in logic has no problem. But why C# does that error?
@m.ghadiri When implementing an interface, you must implement each member exactly. Even if IList<T> was covariant in T (which it isn't), your implementation can't use a more derived T than the interface definition.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.