Mizzrym
Mizzrym

Reputation: 149

Interface using generics "Cannot implicitly convert type"

If i have a class which accepts a generic type derived from IUser, how can i avoid this error message

Cannot implicitly convert type ElimCMS.Service.Users.someclass<ElimCMS.DataModel.Users.User> to ElimCMS.Service.Users.Isomeclass<ElimCMS.DataModel.Users.IUser>. An explicit conversion exists (are you missing a cast?)

Example

   public interface Isomeclass<TUser>
   where TUser : class, IUser
   {

    string test(TUser user);
    TUser returnUser();
   }

   public class someclass<TUser> : Isomeclass<TUser>
   where TUser : class, IUser, new()
   {
    public string test(TUser user)
    {
        string email = user.EMail;
        user.EMail = "changed:" + email;

        return email;
    }


    public TUser returnUser()
    {
        throw new NotImplementedException();
    }
}

 Isomeclass<ElimCMS.DataModel.Users.IUser> servicetest = new someclass<ElimCMS.DataModel.Users.User>();

Upvotes: 1

Views: 3353

Answers (3)

Jesse C. Slicer
Jesse C. Slicer

Reputation: 20157

Change your declaration

public interface Isomeclass<TUser> where TUser : class, IUser
{
    string test(TUser user);
    TUser returnUser();
}

to

public interface Isomeclass<out TUser> where TUser : class, IUser
{
    string test(IUser user);
    TUser returnUser();
}

and redefine the test method appropriately in someclass<TUser> to match.

You can do this if you're using C# 4 (Visual Studio 2010) or greater. That'll get you what you need. If you are using prior versions, well, you'll have to revert to object and do some casting.

Upvotes: 1

Dervall
Dervall

Reputation: 5744

This happens because generics which have different types are not compatible with eachother. To get around this, you can declare your generic parameter to Isomeclass to be covariant using

public interface Isomeclass<out TUser>
   where TUser : class, IUser
{

    string test(TUser user);
    TUser returnUser();
}

However, this will break the test method since it will no longer be type safe. To get around this you can change the paramter user type to IUser and it will work as before.

This is dependent on the version of C# that you are using. For some older versions generics cannot be declared as covariant, which means you have to change the assignment target to be of the same type as the object you assign to it.

Upvotes: 5

O. R. Mapper
O. R. Mapper

Reputation: 20780

Isomeclass<ElimCMS.DataModel.Users.IUser> and someclass<ElimCMS.DataModel.Users.User> are not assignment-compatible. In fact, Isomeclass<ElimCMS.DataModel.Users.IUser> and Isomeclass<ElimCMS.DataModel.Users.User> cannot be assigned to each other.

As you want to use the type specified by a type parameter TUser both as an input and an output parameter, you cannot declare the type argument as covariant or contravariant, so the only solution while keeping the current method signatures in your interface/class seems to be to type your list instance to IUser:

new someclass<ElimCMS.DataModel.Users.IUser>();

or to type your list variable to User:

 Isomeclass<ElimCMS.DataModel.Users.User> servicetest

Upvotes: 2

Related Questions