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);
    }
}