首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为另一个泛型类使用泛型参数类型?

如何为另一个泛型类使用泛型参数类型?
EN

Stack Overflow用户
提问于 2016-11-22 14:59:12
回答 4查看 497关注 0票数 4

对我来说,这看起来像是编译器的错误或一些奇怪的行为。编译器无法确定泛型类中的泛型参数类型

代码

代码语言:javascript
复制
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约束?

编辑:另一个简化示例:

代码语言:javascript
复制
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);
    }
}

另一个例子:

代码语言:javascript
复制
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)
    {
    }
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-11-22 15:15:24

如何使它工作?

1.你能做的就是把它转换成T

代码语言:javascript
复制
BaseHamster hamster = null;
var derived = new DerivedHamster();
T i = derived as T;
var s = new TakeDamageHamster<T>(i);

但是,还需要添加class约束。

代码语言:javascript
复制
class ApplyHitHamster<T> where T : class, IHamster
{
    // Other stuff..
}

2.也可以将构造函数改为使用接口。这也是可行的。

代码语言:javascript
复制
class TakeDamageHamster<T> where T : IHamster
{
    public TakeDamageHamster(IHamster Hamster)
    {
        Console.WriteLine(Hamster.Some);
    }
}

3.或者您可以使用new T()。请记住,这也要求您添加new()约束。

代码语言:javascript
复制
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继承的。

代码语言:javascript
复制
public class DerivedHamster : BaseHamster
{
}

public class AnotherHamster : BaseHamster
{
}

现在我们创建一个ApplyHitHamster实例。

代码语言:javascript
复制
var fooHamster = new ApplyHitHamster<AnotherHamster>();
fooHamster.Zu(); // Let's pretend that the method is public. :)

这将最终尝试创建一个TakeDamageHamster<AnotherHamster>实例。但是等等,您正在尝试将一个DerivedHamster发送到它的构造函数。

代码语言:javascript
复制
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。因此,它不编译。

另一个例子。,假设您初始化类,如下所示:

代码语言:javascript
复制
var fooHamster = new ApplyHitHamster<BaseHamster>();
fooHamster.Zu();

现在TBaseHamster。这会使代码看起来像这样:

代码语言:javascript
复制
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的另一个实现而中断,对吗?所以编译器不允许这样做,仅仅是因为您的约束没有限制这一点。

票数 6
EN

Stack Overflow用户

发布于 2016-11-22 15:11:16

当传递T时,您需要像这样的构造函数,因为T只能是IHamster类型

代码语言:javascript
复制
public TakeDamageHamster(IHamster i)
        {
            // TODO: Complete member initialization
            this.i = i;
        }

公共接口IHamster { int某些{ get;set;}

代码语言:javascript
复制
    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;
        }
    }
票数 0
EN

Stack Overflow用户

发布于 2016-11-22 15:25:09

问题在于这条线。

代码语言:javascript
复制
var s = new TakeDamageHamster<T>(i); 

这个抛出错误的原因是因为不能保证T将是DerivedHamster类型。也就是说,T保证仅为IHamster类型。建议使用以下行。

代码语言:javascript
复制
var s2 = new TakeDamageHamster<DerivedHamster>(derived); 

还可以考虑使用帮助方法来使代码更容易阅读。

代码语言:javascript
复制
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);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40745133

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档