对我而言,它看起来像编译器错误或一些奇怪的行为。 编译器无法确定泛型类
中的泛型参数类型代码
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)
{
}
}
答案 0 :(得分:6)
如何使其有效?
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
并非来自BaseHamster
。
可能是IHamster
的其他几个实现, 派生自BaseHamster
。并且您的代码不应该因为IHamster
的另一个实现被创建,正确而中断?所以编译器不允许这样做,因为你的constaint不限制它。
答案 1 :(得分:0)
当传递T时你需要像这样的构造函数,因为你的T只能是IHamster的类型
public TakeDamageHamster(IHamster i)
{
// TODO: Complete member initialization
this.i = i;
}
公共接口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;
}
}
答案 2 :(得分:0)
问题在于这一行。
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);
}
}
答案 3 :(得分:0)
一切正常。想象一下,你有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
,并仅使用基本接口对其进行初始化。