在Java中我可以轻松地写:
public interface MyInterface<T extends Object>
然后有一个方法在运行时确定T,如:
public MyInterface<?> DetermineObjectAtRuntime()
但是在C#中,<?>
不可用,我需要用类型调用方法;这意味着我需要事先了解类型。
对于那些不确定这是什么的人 - 我有一组数据结构,它们使用不同的枚举作为字段索引器。所有消息都从具有该枚举的公共通用接口扩展为类型变量。现在我需要编写一个方法,从byte []数组中反序列化所有不同类型的消息。
答案 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。