参数约束 - 调用约束类型的调用方法?

时间:2013-10-28 10:20:38

标签: c# generics

我有一个带有通用参数的方法:

internal void DoSomething<T>(T workWithThis)
{
}

我现在想要限制此方法只接受继承我想指定的几个接口之一的参数。但是我还没有找到办法。我想要的是这样的:

internal void DoSomething<T>(T workWithThis) where T : ISomething | ISomethingElse
{
}

显然这不起作用,所以我尝试用静态方法来检查T的类型:

public static bool CheckType(Type t)
{
return */check here*/
}

internal void DoSomething<T>(T workWithThis) where T : CheckType(typeof(T))
{
}

显然这也行不通。问题是为什么?为什么编译器阻止我这样做,基于我的理解,没有理由不使用

4 个答案:

答案 0 :(得分:5)

  

为什么编译器阻止我这样做,基于我的理解,没有理由不这样做

编译器阻止您这样做,因为您尝试执行C#作为语言不支持的操作。您尝试使用的语法不符合C#规范第10.1.5节中的产品。

C#作为一种语言根本不支持您需要的方案。

现在为什么这种语言不允许这种灵活性 - 这归结为正常的平衡行为:

  • 有多少开发人员可以从中受益以及多少
  • 其他开发人员理解更复杂语言的额外负担
  • 设计语言功能,实现和测试
  • 所需的资源(主要在Microsoft内部)

哦,当然这不只是C# - CLR也必须支持这样的限制,它至少会鼓励其他CLR语言理解它。

我建议您通过两种不同的方法来解决这个问题。请注意,它们不能只是泛型方法的重载,因为重载只能通过泛型类型约束来区分。如果你不介意拳击实现接口的值类型,你可以重载:

internal void DoSomething(ISomething something)
{
}

internal void DoSomething(ISomethingElse somethingElse)
{
}

...虽然如果你传入一个表达式是实现两个接口的类型,你最终会出现过载歧义。

或者,只需给这两种方法命名不同。

答案 1 :(得分:2)

编译器必须在编译时验证所有约束,并且不能调用方法来执行此操作。

您可以在where约束中指定的唯一内容是:

  • new() - 需要无参数构造函数
  • class - 必须是参考类型
  • struct - 必须是值类型
  • SomeBaseClass
  • ISomeInterface
  • T : U - 必须是,继承或实施其他通用参数之一

有关详细信息,请参阅C# Programming Guide - Constraints on Type Parameters

至于为什么,你永远不应该回答“我认为没有理由这样做”。你必须从相反的方向开始,“为什么要这样做”,然后提出足够的合理和现实的场景和要求,使其值得实施。见Eric Gunnerson的Minus 100 Points

要在代码中修复此问题,您应该从公共接口派生这两个接口,并在其上添加约束。

如果这两个接口没有任何共同之处,那么我首先会质疑实际添加约束的好处。

例如,如果您的代码要调用与泛型类型/方法一起使用的对象上的方法,那么显然两个接口必须具有相同的概念,该方法是什么,并且唯一的方法是将用于在公共基础接口中定义的方法。这两个接口碰巧具有相同的方法或属性,具有相同的签名,并不会使它成为相同的方法。

话虽如此,您确定在这里需要泛型吗?

如何宣布两个方法,每个方法都采用一个这样的接口?

internal void DoSomething(ISomething workWithThis)
internal void DoSomething(ISomethingElse workWithThis)

答案 2 :(得分:1)

编译器使用泛型约束来确定泛型方法中T上可用的操作 - 因此允许或表达式不是类型安全的。例如,您有两个接口IFirstISecond

public interface IFirst
{
    void First();
}

public interface ISecond
{
    void Second();
}
internal void DoSomething<T>(T workWithThis) where T : IFirst or ISecond
{
    //How to call this method if the type is ISecond
    workWithThis.First();
    //How to call this method if the type is IFirst
    workWithThis.Second();
}

答案 3 :(得分:0)

您可以定义一个包含所有这些内容的空接口。

请记住,在C#接口中可以具有多重继承。

例如:

public interface IHolder : ISomething, ISomethingElse 
{

}

和通用

internal void DoSomething<T>(T workWithThis) where T : IHolder
{
}