我读了很多可能的答案,并没有找到任何符合我需要的答案!
我试图声明一个通用接口,有不同的非通用实现类,然后在同一个上下文中使用这个类。
这是我到目前为止所做的:
接口
public interface WeirdType { }
public class WeirdType1 : WeirdType { }
public class WeirdType2 : WeirdType { }
public interface IGenericInterface<T>
{
T GiveT();
void TakeItBack(T data);
}
实施
public class NonGenericImplementation1 : IGenericInterface<WeirdType1>
{
public WeirdType1 GiveT() { return new WeirdType1(); }
public void TakeItBack(WeirdType1 data) { Console.WriteLine("Got it back 1"); }
}
public class NonGenericImplementation2 : IGenericInterface<WeirdType2>
{
public WeirdType2 GiveT() { return new WeirdType2(); }
public void TakeItBack(WeirdType2 data) { Console.WriteLine("Got it back 2"); }
}
用法
List<IGenericInterface<WeirdType>> implementations = new List<IGenericInterface<WeirdType>>
{
new NonGenericImplementation1(),
new NonGenericImplementation2()
};
foreach (var impl in implementations)
{
WeirdType x = impl.GiveT();
impl.TakeItBack(x);
}
这让我失望
'Argument Type NonGenericImplementation1 is not assignable to IGenericInterface<WeirdType>'
即使一些黑色魔法让我通过编译,它也会在运行时因同样的原因而崩溃。
帮助我理解是什么让C#打字变得不可能和/或建议稍微复杂的模式来顺利完成
我可以用很多不同的方式解决我的实际问题,所以完全替代的解决方案并不是我真正想要的
显然,如果实际答案已经存在,那就是浪费时间
答案 0 :(得分:0)
一如既往,如果没有背景,很难相关,我仍然会尽力帮助。
错误&#39;参数类型NonGenericImplementation1不能分配给IGenericInterface&#39;对我来说似乎完全没问题,在C#中,集合的不同成员必须具有相同的类型。
但你为什么宣布:
<div id="1">test</div>
<div id="2">test</div>
<div id="3">test</div>
<div id="4">test</div>
而不是:
public class NonGenericImplementation1 : IGenericInterface<WeirdType1>
public class NonGenericImplementation2 : IGenericInterface<WeirdType2>
通过这种方式,所有示例代码仍然可以工作,并且两个类都将实现相同的接口,因此您现在可以声明:
public class NonGenericImplementation1 : IGenericInterface<WeirdType>
public class NonGenericImplementation2 : IGenericInterface<WeirdType>
希望它有所帮助。
答案 1 :(得分:0)
即使IGenericInterface<WeirdType1>
实施IGenericInterface<WeirdType>
,WeirdType1
也不是WeirdType
。
答案 2 :(得分:0)
问题在于,如果您从implementations
中取出某些内容,我们就知道它属于IGenericInterface<WeirdType>
类型。这意味着我们应该能够调用GiveT
并获得WeirdType
和TakeItBack
,同时向其传递WeirdType
。
特别是这意味着以下两项都必须有效:
impl.TakeItBack(new WeirdType1());
impl.TakeItBack(new WeirdType2());
现在,如果impl
的类型为NonGenericImplementation1
,则第二个无效,如果类型为NonGenericImplementation2
,则第一个无效。
这意味着我们不得声称NonGenericImplementation1
属于IGenericInterface<WeirdType>
类型且NonGenericImplementation2
属性相同。
答案 3 :(得分:0)
您没有任何实现IGenericInterface的非泛型类。
您的“implements”集合只能接受实现上述接口的类型的对象。
这就是泛型的美丽。它们是强类型的,特别是在处理泛型泛型时,它变得更具挑战性。但是没有办法摆脱它。
首先,Generic List不接受任何未实现IGenericInterface的类型的对象。接下来,当你拥有那种类时,它也不允许使用“WeirdType”类型实例化的对象,即使该类型是从“WeirdType”继承的。
因此,泛型中的继承有助于第一级但不能超越它。
您的问题有解决方案。它不是100%有效的解决方案,许多OOP专家都不会同意这一点,但它有你想要的类结构,它可以按照你想要的方式工作。
您需要创建以下子类。
public class GenericClass<T> : IGenericInterface<T> where T : WeirdType
{
public virtual T GiveT()
{
return default(T);
}
public virtual void TakeItBack(T data)
{
}
}
public class NonGenericClass1 : GenericClass<WeirdType1>, IGenericInterface<WeirdType>
{
public override WeirdType1 GiveT()
{
return new WeirdType1();
}
public void TakeItBack(WeirdType data)
{
Console.WriteLine("Got it back 1");
}
public override void TakeItBack(WeirdType1 data)
{
this.TakeItBack(data);
}
WeirdType IGenericInterface<WeirdType>.GiveT()
{
return GiveT();
}
}
public class NonGenericClass2 : GenericClass<WeirdType2>, IGenericInterface<WeirdType>
{
public WeirdType2 GiveT()
{
return new WeirdType2();
}
public void TakeItBack(WeirdType data)
{
Console.WriteLine("Got it back 2");
}
public override void TakeItBack(WeirdType2 data)
{
this.TakeItBack(data);
}
WeirdType IGenericInterface<WeirdType>.GiveT()
{
return this.GiveT();
}
}
现在您可以初始化Generic接口的集合并将子类的对象添加到其中。
var obj1 = new NonGenericClass1();
var obj2 = new NonGenericClass2();
List<IGenericInterface<WeirdType>> implementations = new List<IGenericInterface<WeirdType>>
{
obj1, obj2
};
foreach (var impl in implementations)
{
WeirdType x = impl.GiveT();
impl.TakeItBack(x);
}
这可以解决您的问题。
答案 4 :(得分:0)
感谢大家的意见,我试着不要重复与T不可知的代码,尽可能减少样板。
我使用的解决方案是添加一个实现额外接口的抽象类。
这不满足我,因为我相信你应该能够为泛型编写类型不可知的代码,因此不需要修改实际的类和接口代码/层次结构,也不会滥用反射。
对于扩展方法和非类型的泛型列表,这是可能的,后者在C#中不受支持。
下面是额外的代码:
public interface IComplexable { void DoComplexStuff(); }
public abstract class GenericImplementation<T> : IGenericInterface<T>, IComplexable
{
public abstract T GiveT();
public abstract void TakeItBack(T data);
public void DoComplexStuff()
{
T x = GiveT();
TakeItBack(x);
}
}
课程声明:
public class NonGenericImplementation1 : GenericImplementation<WeirdType1>
public class NonGenericImplementation2 : GenericImplementation<WeirdType2>
用法:
var impl = new IComplexable[] { new NonGenericImplementation1(),new NonGenericImplementation2() };
foreach (var complexable in impl)
{
complexable.DoComplexStuff();
}