问题
I have the following interface:
public interface IObject
{
double x { get; }
double y { get; }
Holder<IObject> Holder { get; set; }
}
and this class
public class Holder<T> where T : IObject
{
private List<T> items;
public void AddItem(T item){
items.Add(item);
item.Holder = this;
}
However the compiler doesn't like the AddItem method and on this line :
item.Holder = this;
gives me this error:
Cannot convert source type 'Holder<T>' to target type 'Holder<IObject>'
Why can't I do it and what is a good solution for this scenario? thank you
回答1:
You have to bear in mind the way Genrics works in C#, The compiler create a class of the specified type, and because of that you have the error.
To explain more, given the following example:
public class InterfaceImplementation : IObject
{
}
and then some where you do :
var genericInitialisation = new Holder<InterfaceImplementation>();
The compiler at compile time will create a class HolderInterfaceImplementation replacing all accurances of the T generic parameter.
so after compilation you will have this class:
public class HolderInterfaceImplementation
{
private ListInterfaceImplementation items;
public void AddItem(InterfaceImplementation item){
items.Add(item);
item.Holder = this;
}
And item.Holder would be HolderIObject type, so the compiler report an error about not being able to convert HolderInterfaceImplementation to HolderIObject wich is logical.
After explaining the theory the solution comes naturaly and here is an example:
public interface IObject<T> where T : IObject<T>
{
double x { get; }
double y { get; }
Holder<T> Holder { get; set; }
}
public class Holder<T> where T : IObject<T>
{
public Holder()
{
items = new List<T>();
}
private List<T> items;
public void AddItem(T item)
{
items.Add(item);
item.Holder = this;
}
}
public class Implementation : IObject<Implementation>
{
public double x
{
get { return 0; }
}
public double y
{
get { return 0; }
}
public Holder<Implementation> Holder
{
get;
set;
}
}
static void Main(string[] args)
{
var t = new Holder<Implementation>();
t.AddItem(new Implementation());
Console.ReadKey();
}
回答2:
If it was possible to convert that would be a type system hole:
public class Holder<T> where T : IObject
{
public T SomeField;
}
...
var holder = new Holder<IObjectSubType2>();
Holder<IObject> dummy = holder; //assuming that this works
dummy.SomeField = new IObjectSubType1(); //violates type safety
IObjectSubType2 converted = holder.SomeField;
As you can see I was able to convert an instance of IObjectSubType1 to an IObjectSubType2.
That's why this does not type check.
来源:https://stackoverflow.com/questions/19514499/interface-with-generic-object-of-the-interface-type