是否有可能让非泛型方法返回泛型类型?

时间:2013-12-27 23:21:00

标签: c# java generics

在Java中我可以轻松地写:

public interface MyInterface<T extends Object>

然后有一个方法在运行时确定T,如:

public MyInterface<?> DetermineObjectAtRuntime()

但是在C#中,<?>不可用,我需要用类型调用方法;这意味着我需要事先了解类型。

  1. 是否可以从非泛型方法返回泛型类型?
  2. 如果没有,如果我有一个具有该类型的对象实例,我如何计算出调用这种泛型方法的类型?
  3. 对于那些不确定这是什么的人 - 我有一组数据结构,它们使用不同的枚举作为字段索引器。所有消息都从具有该枚举的公共通用接口扩展为类型变量。现在我需要编写一个方法,从byte []数组中反序列化所有不同类型的消息。

4 个答案:

答案 0 :(得分:5)

在没有类型擦除的C#中,有几种方法可以在编译时不知道类型参数:

  • 非通用子集:如果恰好是您需要的MyInterface<T>方法不涉及T,那么您可以将接口的该部分提取到基接口并改为返回基接口。

    Pro:没有运行时类型的恶作剧。

    Con:修改类型(将方法移动到新的基本界面),打破二进制兼容性。

  • 类型检查包装:通过在类型检查后委派给RuntimeTypeCheckedMyInterface<T>来创建实现MyInterface<object>的{​​{1}}类。让方法返回MyInterface<T>,通过将MyInterface<object>包裹在MyInterface<whatever>内创建。

    Pro:适用于任何现有的界面类型,无需修改。

    Con:介绍“T =对象真的意味着对象,还是意味着未知类型”?歧义。

  • 手动类型删除:制作RuntimeTypeCheckedMyInterface的变体,其中没有类似MyInterface<T>的T。让MyInterfaceOfUnknownType继承自MyInterface<T>。让您的方法返回MyInterfaceOfUnknownType

    Pro:行为基本上与Java相同,MyInterfaceOfUnknownType = MyInterfaceOfUnknownType

    Con:使用非泛型方法污染MyInterface<?>。当方法仅因返回类型而不同时,您必须使用名称更改来消除歧义。修改类型(中断源和二进制兼容性)。

  • 搞定类型:让方法返回MyInterface<T>object。有条不紊地适当地施展。

    亲:最初很容易做到。

    Con:难以维持。

答案 1 :(得分:2)

&#34;但在C#中&#39;&lt; ? &GT;&#39;不可用,我需要用类型调用方法;这意味着我需要事先了解类型。&#34;

您可以使用dynamic代替<T>,例如:

dynamic Foo (dynamic Input) {return Input;}

编译器在运行时确定类型。

答案 2 :(得分:1)

另一种方法是添加扩展名

public static class MyExtensions
{
    public static T As<T>(this object obj)
    {
        return (T)obj;
    }
}

以上将为您提供.As()方法

答案 3 :(得分:1)

在C#中,您可以使用通用方法:

class Foo<X>
{
  public T DoSomethingFunky<T>( ... )
  {
    ...
  }
}

但是没有办法使用通配符类型 - C#中的一个大失败。在很多情况下,它会非常有用,因为它是Widget<T>,但你不关心T的细节。

例如,WCF会抛出FaultException<T>,其中T的各种风格都是特定于服务的。如果没有简单地捕获基类FaultException<*>类并使用反射来检查捕获的异常以查看它是否是一个有趣的Exception,则无法捕获T之类的内容。这可以防止以通用方式处理服务故障。

我认为原因是具体的泛型类(Widget<int>)并不是它“继承”的泛型类(Widget<T>)的真正子类型。泛型类只是用作编译新特定类的模板。

您可以做的一件事是让您的通用模板(Widget<T>)继承自非通用基类(Widget)并让您的方法返回:

class AbstractWidget { ... }
class Widget<T> : AbstractWidget { ... }
.
.
.
public Widget GetGeneric Widget()
{
   /* flavor determinated at runtime */
}

调用者有责任决定如何处理其Widget。