我有以下课程:
class Item { }
class MeetingItem : Item { }
class ItemGroup<T> { }
现在,这没有问题:
Item something;
something = new MeetingItem();
然而失败了:
ItemGroup<Item> itemGroup;
itemGroup = new ItemGroup<MeetingItem>(); // Fails here
我收到“无法隐式转换类型'ItemGroup<MeetingItem>
'到'ItemGroup<Item>
'”错误。这不正是我正在做的事情(将类型分配给Item,然后实例化到MeetingItem)?
我最终将拥有ItemGroup类中的Items集合以及其他一些成员。然后我将会有一个包含不同类型派生项的ItemGroups集合。理想情况下,我希望将Item作为一个抽象类(可能是一个接口,我可能需要根据我需要实现的内容保持一个类)。
我对任何重构的想法持开放态度。
感谢。
编辑以在没有Generic ItemGroup的情况下添加我的解决方案: 我决定放弃仿制药......有点......我拼凑了这个:
public class ItemGroup {
public Type ItemType => this.Items.GetType().GetGenericArguments()[0];
public IList Items { get; set; }
public ItemGroup(Type itemType) {
var genericListType = typeof(List<>).MakeGenericType(itemType);
Items = (IList)Activator.CreateInstance(genericListType);
}
}
所以,我现在可以这样做:
List<ItemGroup> groups = new List<ItemGroup>();
groups.Add(new ItemGroup(typeof(MeetingItem));
然后我可以通过以下方式测试特定的Item类型:
groups[0].ItemType == typeof(MeetingItem)
看起来有点hacky,但它确实有效。我对ItemType属性的性能有点担心,我对任何重构的想法持开放态度。
答案 0 :(得分:2)
这是一个方差问题。
考虑一个这样的简单界面:
interface MyInterface<T>
{
T GetStuff();
void SetStuff(T value);
}
现在,您有MyInterface<A>
和MyInterface<B>
,其中B
继承自A
。
返回B
代替A
始终是安全的。但是,返回A
代替B
并不安全。因此,查看GetStuff
时,应该可以将MyInterface<B>
转换为MyInterface<A>
,但反之亦然。
通过B
代替A
始终是安全的。但是,传递A
代替B
是不安全的。因此,查看SetStuff
时,应该可以将MyInterface<A>
转换为MyInterface<B>
,但反之亦然。
问题应该是显而易见的 - 你不能同时实现这两个目标。 两种方法都没有安全演员。
如果您可以避免在单个界面中同时使用这两种方式,则可以使用out
/ in
关键字来指定您的界面支持哪种差异,但这样做是正确的。查看.NET框架中的类:
IEnumerable<object> enumerable = Enumerable.Empty<string>(); // Safe,
// enumerable is covariant
ICollection<object> collection = new Collection<string>(); // Error,
// collection isn't covariant
Func<object> func = () => "Hi!"; // Safe, Func<T> is covariant
Action<object> func = (string val) => { ... }; // Error, Action<T> isn't covariant
另一方面,有逆转:
Func<string> func = () => new object(); // Error, Func<T> isn't contravariant
Action<string> func = (object val) => { ... }; // Safe, Action<T> is contravariant