0

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

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

4 回答 4

5

为什么编译器阻止我这样做,根据我的理解,它没有理由不工作

编译器阻止您这样做,因为您正在尝试做 C# 作为一种语言不支持的事情。您尝试使用的语法不符合 C# 规范第 10.1.5 节中的产生式。

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

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

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

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

我建议你通过两种不同的方法来解决这个问题。请注意,它们不能只是泛型方法的重载,因为重载不能仅因泛型类型约束而有所不同。如果您不介意对实现接口的值类型进行装箱,则可以重载:

internal void DoSomething(ISomething something)
{
}

internal void DoSomething(ISomethingElse somethingElse)
{
}

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

或者,只需给这两种方法起不同的名称。

于 2013-10-28T10:23:15.420 回答
2

编译器必须在编译时验证所有约束,并且不能调用方法来这样做。

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

  • new()- 需要一个无参数的构造函数
  • class- 必须是引用类型
  • struct- 必须是值类型
  • SomeBaseClass
  • ISomeInterface
  • T : U- 必须是、继承自或实现其他泛型参数之一

有关详细信息,请参阅C# 编程指南 - 类型参数的约束。

至于为什么,您永远不必回答“我认为没有理由这样做”。您必须从相反的方向开始,“为什么要这样做”,然后提出足够合理和现实的场景和要求,使其值得实施。请参阅Eric Gunnerson 的《减分 100 分》。

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

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

例如,如果您的代码要在与泛型类型/方法一起使用的对象上调用方法,那么显然两个接口必须对该方法的概念有相同的概念,而这样做的唯一方法是要在公共基本接口中定义的方法。两个接口碰巧声明了相同的方法或属性,并具有相同的签名,但这并不意味着它是相同的方法。

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

仅仅声明两个方法,每个方法都采用一个这样的接口怎么样?

internal void DoSomething(ISomething workWithThis)
internal void DoSomething(ISomethingElse workWithThis)
于 2013-10-28T10:24:09.873 回答
1

编译器使用泛型约束来确定泛型方法中 T 上可用的操作 - 因此允许 or 表达式不是类型安全的。例如,您有两个接口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();
}
于 2013-10-28T10:27:57.050 回答
0

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

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

例如:

public interface IHolder : ISomething, ISomethingElse 
{

}

对于通用

internal void DoSomething<T>(T workWithThis) where T : IHolder
{
}
于 2013-10-28T10:23:58.037 回答