Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 编译时检查值以实现多个接口_C#_Types_Interface - Fatal编程技术网

C# 编译时检查值以实现多个接口

C# 编译时检查值以实现多个接口,c#,types,interface,C#,Types,Interface,假设我想表达“一个方法,它期望一个对象实现接口IFoo和IBar”。比如: void Method(IFoo+IBar param); 我如何用C#来表达这一点? (有句法结构吗?或者是一个好的习语?) 企图 引入一个接口: interface IFooBar : IFoo, IBar {} void Method(IFooBar param); 这太糟糕了,我甚至想到它都很后悔:-)乍一看还行,但可悲的是,它悄悄地引入了一种不应该存在的依赖 IFooBar存在的唯一原因是成为方法接口的

假设我想表达“一个方法,它期望一个对象实现接口IFoo和IBar”。比如:

void Method(IFoo+IBar param);
我如何用C#来表达这一点?

(有句法结构吗?或者是一个好的习语?)


企图 引入一个接口:

interface IFooBar : IFoo, IBar {}

void Method(IFooBar param);
这太糟糕了,我甚至想到它都很后悔:-)乍一看还行,但可悲的是,它悄悄地引入了一种不应该存在的依赖

IFooBar
存在的唯一原因是成为
方法
接口的一部分。因此,任何要用作
方法
参数的对象类都必须知道该方法(以及该接口)存在,否则情况就不会如此。所有实现IFoo和IBar的类都需要修改以实现IFooBar(可能需要了解一个新的程序集)——这是非常不切实际的,如果我们不能修改它们,甚至是不可能的

不必要的依赖=不可能

变通办法 放弃静态键入:

void Method(object param)
{
    if (!param is IFoo)
        throw new ArgumentException("IFoo not supported", "param");
    if (!param is IBar)
        throw new ArgumentException("IBar not supported", "param");

    // ...
}
(或者:在签名中定义一种类型,并动态检查其他类型-如果其中一种类型最重要,但更容易混淆,则更好)

工作正常,但在运行时(无编译时检查)。迫切需要一个医生(每个人都要读)

也仅适用于函数参数。如果我试着在一个字段上使用它,代码会被大量的类型转换填充


这种情况的真实案例?例如
IList
+
INotifyCollectionChanged

公共void somethod(T参数),其中T:IFoo,IBar
public void someMethod<T>(T param) where T : IFoo, IBar
{...}
{...}
我的一个朋友曾经问埃里克·利珀特一个非常类似的问题,他的回答是:

问:C#不允许通过声明变量有什么原因吗 多接口

答:假设我们将其注释为{IFoo,IBar}

问题比声明变量更大。基本上你是 表示要将变量的约束从“ 变量必须是给定类型的“to”变量必须是所有 若干特定类型”。但为什么要停留在变量上呢?如果是这样的话 一个变量的约束,那么它应该是一个类型,句点。你 应该能够说:

List< { IFoo, IBar } > myList; Or
等等。半途而废是没有意义的

这将是类型系统的主要扩展。我们想 支持所有托管语言,而不仅仅是C#和VB。这是 您希望在版本中进入框架的功能类型 一,;做出如此重大的改变既昂贵又困难 当你有四个版本并且拥有数十亿条客户线时 必须继续工作的代码

我自己也经常想要这个功能;我同意这是一个好主意 功能,但我认为现在添加它太贵了。下一个 设计新类型系统时,请从 开始


您可以通过如下定义您的方法来实现

void Method<T>(T param) 
    where T: IFoo, IBar
{
}
void方法(T参数)
其中T:IFoo,IBar
{
}

希望这会有所帮助。

对于方法返回后不会持久化的内容,可以使用受约束的泛型参数。不幸的是,它们有一个很大的局限性。一种方法,例如:

void foo(T param) where T:IFoo,IBar {...} 如果对象支持方法族,请执行以下操作:

void DoSomethingWithMe(IActUpon<T,U> proc); void DoSomethingWithMe(IActUpon<T,U,PT1> proc, ref PT1 p1); void DoSomethingWithMe(IActUpon<T,U,PT1,PT2> proc, ref PT1 p1, ref PT2 p2); 无效剂量(IActUpon proc); 无效剂量与时间(IActUpon proc,参考PT1 p1); 无效剂量与时间(IActUpon proc,参考PT1 p1,参考PT2 p2); 通过创建一个简单的类来实现
IActUpon
的适当变体,可以让对象调用任何需要约束到类型T和U的参数的所需例程


不幸的是,虽然这种方法几乎是通用的(最大的限制是必须为任何特定数量的泛型参数显式编码),但充其量也很尴尬。有了一些编译器支持,它可能不会太糟糕,但是对于一般用途来说,它可能太讨厌了。

谢谢你的回答,我喜欢泛型方法的解决方法:-)可惜我没有泛型属性。我想当我需要时,我会使用一个通用的
getX()
/
setX()
对。 interface IActUpon<T,U> { void DoSomething<MT>(ref MT it) where MT:T,U; } interface IActUpon<T,U,PT1> { void DoSomething<MT>(ref MT it, ref PT1 p1) where MT:T,U; } interface IActUpon<T,U,PT1,PT2> { void DoSomething<MT>(ref MT it, ref PT1 p1, ref PT2 p2) where MT:T,U; } void DoSomethingWithMe(IActUpon<T,U> proc); void DoSomethingWithMe(IActUpon<T,U,PT1> proc, ref PT1 p1); void DoSomethingWithMe(IActUpon<T,U,PT1,PT2> proc, ref PT1 p1, ref PT2 p2);