C#中使用泛型类型实例化通用对象

3

我正在编写一个通用的委托函数,并声明返回类型为List。

public static List<T> PerformOperationOnGenericArray<T>(IList<T> myList,
    FunctionForGenericArray<T> operation)

我能否使用一个通用的返回类型代替List,并指定一个泛型类型,比如S?

public static S<T> PerformOperationOnGenericArray<T, S>(IList<T> myList, 
    FunctionForGenericArray<T> operation)

我猜这是不可能的,但我看不出为什么不行。编译器当我指定类型时肯定知道它的类型:

PerformOperationOnGenericArray<int, List<string>>(myInts, i => i.Equals(12));

也许这是一个需要考虑使用动态类型的情况吗?

1个回答

4

您不能将开放式泛型类型用作泛型类型参数,但是您可以使用特定类型S<T>作为参数:

public static R PerformOperationOnGenericArray<T,R>
           (IList<T> myList, FunctionForGenericArray<T> operation) 
    where R : S<T>

在您的情况下,如果类型S在编译时是完全定义的(闭合类型),您甚至不需要这样做:
public static S<T> PerformOperationOnGenericArray<T>
           (IList<T> myList, FunctionForGenericArray<T> operation) 

应该足够了。

只有在S本身会变化时,您才需要使用第一种形式。那么我是什么意思呢?让我们看一个例子。如果您有:

class Foo<T> { }

你可以写:

public static Foo<T> PerformOperationOnGenericArray<T>
           (IList<T> myList, FunctionForGenericArray<T> operation)

但是,如果您有一些相关的通用类型组:

class Foo<T> { }
class Bar<T> : Foo<T> { }
class Baz<T> : Foo<T> { }

如果您希望允许调用者指定要使用哪个,那么您需要将返回类型作为方法的泛型签名的一部分:

public static R PerformOperationOnGenericArray<T,R>
           (IList<T> myList, FunctionForGenericArray<T> operation) 
    where R : Foo<T>

现在,调用者需要明确指定R的类型:

PerformOperationOnGenericArray<T,Bar<T>>( ... )

如果您想允许任何接受单个参数的通用类型被允许,那么您将没有运气。类型系统无法提供表达限制的方式:
允许任何允许单个参数的泛型类型,并强制该参数为 T。
最好的方法是定义一个众所周知的接口,所有已知类型都符合(例如 IEnumerable 或自己创建的接口),并将其用作泛型约束的一部分。
public static R PerformOperationOnGenericArray<T,R>
           (IList<T> myList, FunctionForGenericArray<T> operation) 
    where R : IEnumerable<T>

然而,在这种情况下,提供的类型必须全部实现此接口。如果您正在寻找前者(其中可以指定任何类型,只需匹配类型参数的数量),则需要使用通用的鸭子类型(1) - C#不支持此功能。
关于这个问题有一个有趣的侧面说明。尽量避免创建无法从方法的形式参数中仅由编译器推断出类型的通用方法。当无法推断出参数时,调用者被迫指定所有类型参数 - 这会导致混乱和冗长的代码。虽然有时确实会遇到这些情况,但在可能的情况下最好避免它们。 (1) - C#在单个程序集中的匿名类型中支持鸭子类型,如果类型按成员的顺序、类型和名称匹配,编译器将假定它们是相同的类型。

谢谢您的回复。不幸的是,我已经尝试了您的第二个建议,但编译器不喜欢 S。我收到了“未知实体'S'”的错误提示。 - Ryan Tomlinson
@Ryan - 第二种形式要求 S 是一个实际的类型。它不是一个类型参数。如果 S 本身就是一个类型参数,那么你必须使用第一种形式。我会更新我的答案以使其更清晰明了。 - LBushkin
啊..抱歉我误解了你的意思。现在明白了,感谢你的澄清。这不是要投入生产的东西。只是在研究委托函数的通用类型边界。 - Ryan Tomlinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接