C# 如何为另一个泛型类使用泛型参数类型?
对我来说,它看起来像一个编译器错误或一些奇怪的行为。 编译器无法确定泛型类中的泛型参数类型 代码 另一个例子:C# 如何为另一个泛型类使用泛型参数类型?,c#,.net,generics,C#,.net,Generics,对我来说,它看起来像一个编译器错误或一些奇怪的行为。 编译器无法确定泛型类中的泛型参数类型 代码 另一个例子: public class BaseHamster { public int Some { get; set; } } class ApplyHitHamster<T> where T : BaseHamster, new() // MSDN: { void Zu() { var hamster = new BaseHamste
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)
{
}
}
公共类Base仓鼠
{
公共int Some{get;set;}
}
类applyHithaster,其中T:base仓鼠,new()//MSDN:
{
void Zu()
{
var仓鼠=新的Base仓鼠();
超级方法(仓鼠);//当通过T时,你需要像这样的构造函数,因为你的T只能是IHamster类型
public TakeDamageHamster(IHamster i)
{
// TODO: Complete member initialization
this.i = i;
}
公共接口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
{
private IHamster i;
public TakeDamageHamster(T Hamster)
{
Console.WriteLine(Hamster.Some);
}
public TakeDamageHamster(IHamster i)
{
// TODO: Complete member initialization
this.i = i;
}
}
公共抽象类Base仓鼠:IHamster
{
公共int Some{get;set;}
}
公共类衍生仓鼠:基础仓鼠
{
}
类applyhithaster在哪里T:IHamster/如何使其工作?
1.你能做的就是将它转换为T
BaseHamster hamster = null;
var derived = new DerivedHamster();
T i = derived as T;
var s = new TakeDamageHamster<T>(i);
2.或者,您可以将构造函数更改为使用接口。这也会起作用
class TakeDamageHamster<T> where T : IHamster
{
public TakeDamageHamster(IHamster Hamster)
{
Console.WriteLine(Hamster.Some);
}
}
为什么不起作用?
因为约束不能保证i
实际上是从T
派生出来的。假设我们创建了一个另一个仓鼠
。请注意,它继承自Base仓鼠
,但不继承自derived仓鼠
public class DerivedHamster : BaseHamster
{
}
public class AnotherHamster : BaseHamster
{
}
var fooHamster = new ApplyHitHamster<AnotherHamster>();
fooHamster.Zu(); // Let's pretend that the method is public. :)
现在我们创建一个applyhithaster
的实例
public class DerivedHamster : BaseHamster
{
}
public class AnotherHamster : BaseHamster
{
}
var fooHamster = new ApplyHitHamster<AnotherHamster>();
fooHamster.Zu(); // Let's pretend that the method is public. :)
请记住,i
是一只衍生仓鼠
,但是TakeDamage仓鼠
期望另一只仓鼠
。因此它不会编译
另一个例子。假设您这样初始化类:
var fooHamster = new ApplyHitHamster<BaseHamster>();
fooHamster.Zu();
它不会编译,因为takedamage仓鼠
需要一个base仓鼠
(或者从它派生的东西)作为它的构造函数的一个参数。但是您将向它发送一个IHamster
。它们不是相同的东西,即使BaseHamster
实现IHamster
IHamster
并不是从BaseHamster
派生出来的
public class DerivedHamster : BaseHamster
{
}
public class AnotherHamster : BaseHamster
{
}
var fooHamster = new ApplyHitHamster<AnotherHamster>();
fooHamster.Zu(); // Let's pretend that the method is public. :)
可能还有其他几个IHamster
的实现,它们不是源于BaseHamster
。你的代码不应该仅仅因为另一个IHamster
的实现被创建而中断,对吧?所以编译器不允许这样做,只是因为你的构造函数没有限制这一点。问题在于这条线
var s = new TakeDamageHamster<T>(i);
var s=newtakedamage仓鼠(i);
这引发错误的原因是,无法保证T为Derived仓鼠类型。也就是说,T仅保证为IHamster类型。建议使用以下行
var s2 = new TakeDamageHamster<DerivedHamster>(derived);
var s2=新的TakeDamage仓鼠(衍生);
还考虑使用帮助器方法使代码更容易阅读。
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);
}
}
类applyhisamster,其中T:IHamster
{
void Zu()
{
var派生=新派生仓鼠();
var s2=新的TakeDamage仓鼠(衍生);
var s3=CreateTakeDamage仓鼠(衍生);
}
TakeDamage仓鼠创建TakeDamage仓鼠(T2 hammie)
T2:IHamster在哪里
{
返回新的Takedamage仓鼠(哈米);
}
}
工作正常。假设您有ApplyHithaster
。现在,Zu
的内容展开到:
IHamster i = derived;
var s = new TakeDamageHamster<DerivedHamster>(i);
现在,您可以使用所需的任何通用参数创建TakeDamage仓鼠
,并仅使用基本接口对其进行初始化。来自Java后台,发生这种情况是因为您正在执行未经检查的操作。通常这些警告可以被抑制。发生这种情况是因为编译器无法预测类型。TakeDamage仓鼠
在构造时需要一个T
实例,但您提供的是IHamster
实例,因此无法正确编译。您需要提供T
实例作为Zu
的参数,或者通过添加new()
在applyhithaster
中对T
的约束。我不使用我在where is基类中使用的另一个仓鼠。并且使用特殊构造函数不是我想要的。我只是告诉你为什么它不会编译。它不会编译,因为T
并不总是派生自derivedhaster
。两者都将派生自de>IHamster
,但这不是您用来作为constructor参数的。在takedamage仓鼠
@kalashn1k0v-是的,但您没有将T
发送给takedamage仓鼠的构造函数。您发送的是派生仓鼠
。而派生仓鼠
不一定来自>T
。在您的示例中,这是因为您没有其他的BaseHamster
实现。但是编译器不知道这一点。而且它不应该因为您添加了另一个实现而中断。@kalashn1k0v-T
不保证是BaseHamster
,因为客户端选择了T
,并且还可以添加T他们自己的IHamster
实现。如果您只想有多个可能的参数类型T
,那么您根本不需要泛型。@kalashn1k0v-其中T:base仓鼠
确保T
是base仓鼠
的子类型,但它不确保base仓鼠
是一个微妙的子类型这是你需要做的s.Method(新的Base仓鼠())
。
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);
}
}
IHamster i = derived;
var s = new TakeDamageHamster<DerivedHamster>(i);
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);
}
}