[英]How to use generic parameter type for another generic class?
对我来说,它看起来像编译器错误或一些奇怪的行为。 编译器无法确定泛型类中的泛型参数类型
码
public interface IHamster
{
int Some { get; set; }
}
public abstract class BaseHamster : IHamster
{
public int Some { get; set; }
}
public class DerivedHamster : BaseHamster
{
}
class ApplyHitHamster<T> where T : IHamster // <-- same constraint
{
void Zu()
{
BaseHamster hamster = null;
var derived = new DerivedHamster();
IHamster i = derived;
var s = new TakeDamageHamster<T>(i); // <<<< Compilation Error on any variables(hamster,derived,i) WHY?????????
var s2 = new TakeDamageHamster<IHamster>(i); // <<<< But THIS works well
}
}
class TakeDamageHamster<T> where T : IHamster // <-- same constraint
{
public TakeDamageHamster(T Hamster)
{
Console.WriteLine(Hamster.Some);
}
}
它怎么可能使用<T>
与同where
的约束,而不是<IHamster>
直接约束?
为什么编译器不能确定类型,如果两个类都具有相同的where T : IHamster
约束?
编辑:另一个简化的例子:
public class BaseHamster
{
public int Some { get; set; }
}
public class DerivedHamster : BaseHamster
{
}
class ApplyHitHamster<T> where T : BaseHamster, new() // <-- same constraint
{
void Zu()
{
BaseHamster hamster = new BaseHamster();
var derived = new DerivedHamster();
var s = new TakeDamageHamster<T>();
s.Method(hamster); // <<<< Compilation Error on any variables(hamster,derived) WHY?????????
}
}
class TakeDamageHamster<T> where T : BaseHamster, new() // <-- same constraint
{
public void Method(T hamster)
{
Console.WriteLine(hamster.Some);
}
}
另一个例子:
public class BaseHamster
{
public int Some { get; set; }
}
class ApplyHitHamster<T> where T : BaseHamster, new() // MSDN:
{
void Zu()
{
var hamster = new BaseHamster();
SuperMethod(hamster); // <<<< WTF? T is ALWAYS BaseHamster!!!
SuperMethod(hamster as T);
}
void SuperMethod(T x)
{
}
}
如何使它工作?
1.你可以做什么,使工作是将其转换为T
。
BaseHamster hamster = null;
var derived = new DerivedHamster();
T i = derived as T;
var s = new TakeDamageHamster<T>(i);
但是,您还需要添加class
约束。
class ApplyHitHamster<T> where T : class, IHamster
{
// Other stuff..
}
2.或者,您可以更改构造函数以使用该接口。 那也行。
class TakeDamageHamster<T> where T : IHamster
{
public TakeDamageHamster(IHamster Hamster)
{
Console.WriteLine(Hamster.Some);
}
}
3.或者你可以使用new T()
。 请记住,这还需要您添加new()
约束。
BaseHamster hamster = null;
var derived = new T();
var s = new TakeDamageHamster<T>(derived); // <<<< Compilation Error on any variables(hamster,derived,i) WHY?????????
var s2 = new TakeDamageHamster<IHamster>(derived); // <<<< But THIS works well
为什么它不起作用?
因为约束不能保证i
实际上是从T
派生的。 假设我们创建了一个AnotherHamster
。 请注意,它继承自BaseHamster
,但不是来自DerivedHamster
。
public class DerivedHamster : BaseHamster
{
}
public class AnotherHamster : BaseHamster
{
}
现在我们创建一个ApplyHitHamster
实例。
var fooHamster = new ApplyHitHamster<AnotherHamster>();
fooHamster.Zu(); // Let's pretend that the method is public. :)
这将最终尝试创建TakeDamageHamster<AnotherHamster>
的实例。 但是等等,你正在尝试将DerivedHamster
发送给它的构造函数。
BaseHamster hamster = null;
var derived = new DerivedHamster();
IHamster i = derived;
// You cannot send DerivedHamster when it expects AnotherHamster.
var s = new TakeDamageHamster<T>(i); // T is now AnotherHamster.
记住i
是DerivedHamster
,但TakeDamageHamster<AnotherHamster>
期望一个AnotherHamster
。 因此它不编译。
另一个例子。 假设你像这样初始化你的类:
var fooHamster = new ApplyHitHamster<BaseHamster>();
fooHamster.Zu();
现在T
是BaseHamster
。 这将使代码看起来像这样:
var derived = new DerivedHamster();
IHamster i = derived;
var s = new TakeDamageHamster<BaseHamster>(i); // Cannot pass IHamster when ctor expects BaseHamster.
它不会编译,因为TakeDamageHamster
期望BaseHamster
(或从它派生的东西)作为它的构造函数的参数。 但你发送的是IHamster
。 即使BaseHamster
实现了IHamster
,它们也不是IHamster
。 IHamster
不是从BaseHamster
派生的。
IHamster
可能还有其他一些实现,它们不是从BaseHamster
派生的。 并且你的代码不应该因为创建IHamster
另一个实现而IHamster
, 对吧 ? 所以编译器不允许这样做,因为你的constaint不限制它。
当传递T你需要像这样的构造函数,因为你的T只能是IHamster的类型
public TakeDamageHamster(IHamster i)
{
// TODO: Complete member initialization
this.i = i;
}
public interface IHamster {int Some {get; 组; }}
public abstract class BaseHamster : IHamster
{
public int Some { get; set; }
}
public class DerivedHamster : BaseHamster
{
}
class ApplyHitHamster<T> where T : IHamster // <-- same constraint
{
void Zu()
{
BaseHamster hamster = null;
var derived = new DerivedHamster();
IHamster i = derived;
var s = new TakeDamageHamster<T>(i); // <<<< Compilation Error on any variables(hamster,derived,i) WHY?????????
var s2 = new TakeDamageHamster<IHamster>(i); // <<<< But THIS works well
}
}
class TakeDamageHamster<T> where T : IHamster // <-- same constraint
{
private IHamster i;
public TakeDamageHamster(T Hamster)
{
Console.WriteLine(Hamster.Some);
}
public TakeDamageHamster(IHamster i)
{
// TODO: Complete member initialization
this.i = i;
}
}
问题出在这条线上。
var s = new TakeDamageHamster<T>(i);
之所以抛出错误是因为无法保证T的类型为DerivedHamster。 也就是说,T保证只是IHamster类型。 建议使用以下行。
var s2 = new TakeDamageHamster<DerivedHamster>(derived);
还要考虑使用辅助方法使代码更容易阅读。
class ApplyHitHamster<T> where T : IHamster
{
void Zu()
{
var derived = new DerivedHamster();
var s2 = new TakeDamageHamster<DerivedHamster>(derived);
var s3 = CreateTakeDamageHamster(derived);
}
TakeDamageHamster<T2> CreateTakeDamageHamster<T2>(T2 hammie)
where T2 : IHamster
{
return new TakeDamageHamster<T2>(hammie);
}
}
它运作正常。 想象一下,你有ApplyHitHamster<DerivedHamster>
。 现在, Zu
内容解除了:
IHamster i = derived;
var s = new TakeDamageHamster<DerivedHamster>(i);
你可以清楚地看到TakeDamageHamster
ctor需要DerivedHamster
而你正试图将裸IHamster
传递给它。 它不能工作。
如果你希望你的Zu
工作原样,你需要做:
class TakeDamageHamster<T> where T : IHamster // <-- same constraint
{
public TakeDamageHamster(IHamster Hamster)//<-- now this is compatible with constraint alone, no matter what T is.
{
Console.WriteLine(Hamster.Some);
}
}
现在,您可以使用TakeDamageHamster
的任何通用参数创建TakeDamageHamster
,并仅使用基本接口对其进行初始化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.