【问题标题】:Returning generic without knowing type在不知道类型的情况下返回泛​​型
【发布时间】:2012-09-19 11:09:34
【问题描述】:

我有一个类在其泛型类型参数中接受某个对象类型的实例。布局是这样的:

public abstract BaseClass { ... }
public DiamondClass : BaseClass { ... }
public SilverClass : BaseClass { ... }

public Handler<T> where T : BaseClass { ... }

我希望能够创建一个方法来返回Handler&lt;DiamondClass&gt;Handler&lt;BaseClass&gt; 的实例,而无需在输入时定义类型。我已经尝试过这些方面的一些东西:

public Handler<BaseClass> GetHandler(HandlerType type)
{
    switch(type)
    {
        case HandlerType.Diamond: return new Handler<DiamondClass>();
        case HandlerType.Silver: return new Handler<SilverClass>();
        default: throw new InvalidOperationException("...");
    }
}

但这不起作用,因为显然Handler&lt;DiamondClass&gt; 不会隐式转换为Handler&lt;BaseClass&gt;。我可以这样指定:

public Handler<T> GetHandler<T>(HandlerType type) where T : BaseClass
{
    switch(type)
    {
        case HandlerType.Diamond: return (Handler<T>)new Handler<DiamondClass>();
        case HandlerType.Silver: return (Handler<T>)new Handler<SilverClass>();
        default: throw new InvalidOperationException("...");
    }
}

但现在我需要致电GetHandler&lt;DiamondClass&gt;GetHandler&lt;BaseClass&gt;。这违背了拥有一个基于枚举返回正确处理程序的方法的目的,而不知道类型。我希望我可以定义一个Type 对象并传递它,如下所示:

 Type objType = typeof(DiamondClass);
 var handler = Handler<objType>();

但显然 C# 不允许这种愚蠢行为。我已经采取了几种不同的方式,我想有办法做到这一点,但我很难过。


(实际上,我确实通过返回 dynamic 对象来实现这一点,但我想尽可能避免它,因为它失去了任何类型安全和 Intellisense 支持。)

【问题讨论】:

  • var handler = Handler&lt;DiamondClass&gt;(); 有什么问题,我看不出你要解决什么问题。
  • 如果你必须检查泛型方法内部的类型,我总是会质疑这种方法的有用性。
  • @RobA 请记住,为了便于解释,我对示例进行了很多简化。部分问题是我希望它属于用户控件,我不能将其定义为通用的,因为它会扼杀设计者。

标签: c# generics inheritance types factory


【解决方案1】:

这就是协变发挥作用的地方,协变和逆变只适用于接口和委托,因此,要解决您的问题,只需将新接口IHandler定义为co-variant 与 out 指定类型参数是协变的:

public interface IHandler<out T> where T : BaseClass 
{
}

具有协变类型参数的接口使其方法能够返回比类型参数指定的派生类型更多的派生类型

它会起作用的。更多信息是here

【讨论】:

  • 嘿,我不知道我们可以用 类型做到这一点!凉豆。我喜欢学习这些东西。编辑:刚试了一下。你是救生员。它比我认为我必须做的更简化了概念。我想知道为什么它不接受孩子作为基地的一种类型。
  • @KChaloux:因为如果我理解正确的话,这些东西只适用于 INTERFACE 和 DELEGATE? 作为基类的子类是什么意思?
  • 我使用对象作为类型参数,而不是主要类型。所以在示例中,DiamondClassSilverClassBaseClass 的子代,因此与 BaseClass 的类型具有“是”关系。 DiamondClassBaseClass... 这听起来令人困惑,因为我已经输入了它。
  • @KChaloux:还有一件事,这个东西只适用于引用类型,而不是值类型。还是不明白你的问题:“为什么不接受?”
  • 我基本上只是说我不明白为什么编译器不允许从 Handler => Handler 进行隐式转换。现在我想我明白了。 (我不是想在 cmets 中问另一个问题,只是发表声明)。
猜你喜欢
  • 1970-01-01
  • 2017-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多