对我来说,这看起来像是编译器的错误或一些奇怪的行为。编译器无法确定泛型类中的泛型参数类型
代码
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);
}
}如何才能使用具有相同where约束而不是<IHamster>直接约束的<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)
{
}
}发布于 2016-11-22 15:15:24
如何使它工作?
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的另一个实现而中断,对吗?所以编译器不允许这样做,仅仅是因为您的约束没有限制这一点。
发布于 2016-11-22 15:11:16
当传递T时,您需要像这样的构造函数,因为T只能是IHamster类型
public TakeDamageHamster(IHamster i)
{
// TODO: Complete member initialization
this.i = i;
}公共接口IHamster { int某些{ 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
{
private IHamster i;
public TakeDamageHamster(T Hamster)
{
Console.WriteLine(Hamster.Some);
}
public TakeDamageHamster(IHamster i)
{
// TODO: Complete member initialization
this.i = i;
}
}发布于 2016-11-22 15:25:09
问题在于这条线。
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);
}
}https://stackoverflow.com/questions/40745133
复制相似问题