4 回答
你的问题是你不能链接用户定义的隐式转换。乍一看,您似乎应该可以从Reference<Circle>
-> Reference<Shape>
via Reference<Circle>
-> Circle
-> Shape
->开始Reference<Shape>
。但是,您将使用两个用户定义的隐式强制转换。首先你会从Reference<Circle>
-> Circle
viaoperator T(Reference<T> value)
去。然后你会从
Shape
-> Reference<Shape>
via去operator Reference<T>(T value)
。您可以通过扩展创建 Add 方法的重载来解决此问题List
。这将使您可以自由地在Reference.Add
. 现在,您不必链接用户定义的隐式强制转换运算符。
请参阅有关用户定义的隐式强制转换的规范:http: //msdn.microsoft.com/en-us/library/aa691302 (v=vs.71).aspx
//You can get around your inability to chain user defined implicit casts
//by creating a ReferenceList<T> that extends List<IReference<T>>
//and overloads the List.Add method
public class ReferenceList<T> : List<IReference<T>> where T : MyAbstractBase
{
//With this overload you can accept a T. Then explicity cast to Reference<T>
//by using operator Reference<T>(T value)
public void Add(T item)
{
base.Add((Reference<T>)item);
}
}
List<Reference<Shape>> shapeList = new List<Reference<Shape>>();
ReferenceList<Shape> shapeList2 = new ReferenceList<Shape>();
List<IReference<Shape>> shapeList3 = new List<IReference<Shape>>();
//Interesting cases that should work with the OP
//Works for obvious reasons
shapeList.Add(new Reference<Shape>());
//Works because you're using one user defined implicit cast
//where the cast is operator Reference<T>(T value).
//Shape -> Reference<Shape>
shapeList.Add(new Shape());
//Works because you're using one non user defined implicit cast and one user defined
//implicit cast where the user defined implicit cast is operator Reference<T>(T value)
//Circle -> Shape -> Wrapper<Shape>
shapeList.Add(new Circle());
//Does not work because you need to chain two user defined implicit casts
//where the implicit casts are operator T(Reference<T> value) and operator Reference<T>(T value)
//Reference<Circle> -> Circle -> Shape -> Reference<Shape>
//Theoretically this could work, but the C# specs state that chaining user defined
//implicit casts is not allowed in C# (See link below)
shapeList.Add(new Reference<Circle>());
//This case works for similiar reasons that shapeList.Add(new Circle()). It uses
//only one user defined implicit cast because you're calling operator T(Reference<T> value)
//explicitely
shapeList.Add(new (Circle)Reference<Circle>());
//Interesting cases for ReferenceList
//Works because this calls List.Add which accepts a Reference<T>
shapeList2.Add(new Reference<Shape>());
//Works because this calls ReferenceList.Add wich accepts a T
shapeList2.Add(new Circle());
//Works because this calls ReferenceList.Add wich accepts a T.
//and Reference<Circle> can be implicitly cast to a Circle via
//operator T(Reference<T> value).
//Reference<Circle> -> Circle -> Shape -> Reference<Shape> where
//the last cast is done explicitely in the ReferenceList.Add method
//via operator Reference<T>(T value)
shapeList2.Add(new Reference<Circle>());
//Interesting cases for List<IReference<Shape>>
//Works for obvious reasons
shapeList3.Add(new Reference<Shape>());
//Works because IReference is covariant. In C# interfaces can be
//covariant. Classes cannot be covariant.
shapeList3.Add(new Reference<Circle>());
//Does not work because C# does not support user defined implicit
//casts to interface. In other words, you implicitly cast Shape -> Reference<Shape>
shapeList3.Add(new Shape());
//Doesn't work for similiar reasons to why shapeList3.Add(new Shape()) doesn't work
shapeList3.Add(new Circle());
好的,这是黑暗中的一个镜头,至少应该让你的隐式运算符编译。我没有任何设置可以立即对其进行测试。不过,它应该可以工作。将此添加到 Reference 类。
public static implicit operator Reference<myAbstractBase>(Reference<T> i)
{
return i;
}
请注意,这里缺少类型检查,因此如果 T不是从 myAbstractBase 派生的,您可能会被淹没。
我已经开始定义一个完全是内部的自定义集合的路径List<Reference<T>>
,但它似乎在做诀窍:
public class ReferenceCollection<T> : ICollection<T> where T : myAbstractBase
{
private List<Reference<T>> collection = new List<Reference<T>>();
public IEnumerable<T> toIEnumerable()
{
return (IEnumerable<T>) collection.Select(r => r.Value);
}
public IEnumerator<T> GetEnumerator()
{
return toIEnumerable().GetEnumerator(); ;
}
#region ICollection<T> Members
public void Add(T item)
{
collection.Add(item);
}
...
}
现在我可以拨打以下电话(我以前不能这样做):
ReferenceCollection<shape> test = new ReferenceCollection<shape>();
test.Add(new circle());
为什么它以这种方式工作而不是另一种方式?我真的在做完全不同的事情吗?也许转换实际上现在以相反的顺序发生(圆形被转换为形状,然后形状被隐式转换为,Resource<shape>
因为它被添加到内部集合中。)
我还看不到这种方法有任何缺点。我什至可以定义隐式转换器以将 aReferenceCollection<T>
直接转换为 aList<T>
或List<Reference<T>>
无需对其进行迭代。不过,我想知道是否有一种方法可以定义原始类,以便在隐式转换之前类似地发生强制转换以避免不可强制转换的包装类型。
我重新表述了这个问题并在另一个线程中得到了答案:如何将 Generic<T> 转换为 Generic<R> 其中 T 是 R 的子类?
诀窍是创建一个协变接口IReference<out T>
,并在使用类型的任何地方始终使用该接口。所以声明List<IReference<myAbstractBase>>
而不是List<Reference<myAbstractBase>>
. 关于为什么这在泛型中的协变和逆变中起作用的详细信息