m.ghadiri
m.ghadiri

Reputation: 330

C# - Implemented class from its interface, doesn't match

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?

Upvotes: 1

Views: 625

Answers (4)

Christoph Fink
Christoph Fink

Reputation: 23103

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; }
}

Upvotes: 2

Matt Burland
Matt Burland

Reputation: 45135

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.

Upvotes: 3

Iridium
Iridium

Reputation: 23721

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; }

Upvotes: 1

Claudio Redi
Claudio Redi

Reputation: 68400

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; }

Upvotes: 3

Related Questions