简体   繁体   中英

Cannot implicitly convert type when using generics

I am trying to set a value on a base class but am getting the error:

Cannot implicitly convert type 'PersonService' to 'IMyInterface<IEntity>' . An explicit conversion exists (are you missing a cast?)

When I try to create my PersonService() it does implement IMyInterface<Person> . Person implements IEntity so I can't work out why it is not working.

public interface IEntity { }
public class Person : IEntity { }
public interface IMyInterface<T> where T : IEntity { }
public class PersonService : IMyInterface<Person> { }
public abstract class Model : IEntity
{
    public IMyInterface<IEntity> DataService { get; set; }
}
public class Test : Model
{
    public Person Person { get; set; }
    public Test() : base()
    {
        DataService = new PersonService();
    }
}

An IMyInterface<Person> isn't necessarily compatible with an IMyInterface<IEntity> . What if IMyInterface contains an .Add(T item) method? If you were allowed to call that through IMyInterface<IEntity> for something that's not a Person , the collection would end up with an invalid element, violating type safety.

But what if IMyInterface contains no such methods, and it's always safe? In that case you can tell the compiler that by using a covariant type:

public interface IMyInterface<out T> where T : IEntity { }

And now your example will compile.

You need to make your interface co-variant (if it's possible):

public interface IMyInterface<out T> where T : IEntity { }

Then you would be able to do:

DataService = new PersonService();

Because DataService is expecting an IMyInterface<IEntity> not an IMyInterface<Person> .

Other answers regarding covariance are a great way to solve this - another is to introduce some generics.

If you change Model like this to specify the type of entity

public abstract class Model<TEntity> : IEntity 
            where TEntity : IEntity
{
    public IMyInterface<TEntity> DataService { get; set; }
}

and Test like this:

public class Test : Model<Person>
{
    public Person Person { get; set; }
    public Test() : base()
    {
        DataService = new PersonService();
    }
}

All works as expected:

http://rextester.com/EVBT53292

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM