Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.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#_Generics_Type Constraints - Fatal编程技术网

是否可以将C#泛型方法类型参数约束为;可转让自;包含类';类型参数?

是否可以将C#泛型方法类型参数约束为;可转让自;包含类';类型参数?,c#,generics,type-constraints,C#,Generics,Type Constraints,我怀疑答案是否定的,但我想知道是否有可能这样做: public class MyGenericClass<TSomeClass> { public void MyGenericMethod<TSomeInterface>() // This doesn't compile. where TSomeClass : TSomeInterface { //... } } 这或多或少地强制了我想要的约束

我怀疑答案是否定的,但我想知道是否有可能这样做:

public class MyGenericClass<TSomeClass> {
    public void MyGenericMethod<TSomeInterface>() 
        // This doesn't compile.
        where TSomeClass : TSomeInterface 
    {
        //...
    }
}
这或多或少地强制了我想要的约束(即
TSomeClass
必须继承自,或者在接口的情况下,实现,
TSomeInterface
),但是调用它是非常笨拙的,因为我必须指定
TIntermediateType
(尽管我确实希望它根据
TSomeClass
进行计算):

var myGenericInstance=new MyGenericClass();
myGenericInstance.MyGenericMethod(TSomeClass,TSomeInterface);
此外,上述破解被破解,因为调用方理论上可以指定
TSomeClass
的子类作为第一个类型参数,其中只有子类实现
TSomeInterface

我之所以要这样做是因为我正在为WCF服务编写一个流畅的工厂模式,并且我希望防止调用方(在编译时)尝试使用服务类未实现的约定创建端点。我显然可以在运行时检查这一点(WCF实际上为我做了这一点),但我非常喜欢编译时检查


有没有更好/更优雅的方法来实现我在这里所追求的目标?

我之所以能够理解为什么它无法编译,原因如下:

假设此程序编译:

class Program {
    class Class1 { }
    class Class2 { }
    public class MyGenericClass<TSomeClass> {
        public void MyGenericMethod<TSomeInterface>() where TSomeClass : TSomeInterface {
        }
    }
    static void Main(string[] args) {
        var inst = new MyGenericClass<Class1>();
    }
}
编译器会抱怨
Class1
没有实现
Class2
。但是,哪一行是错的?约束是在调用
MyGenericMethod
时,但有问题的代码行是创建
MyGenericClass

换句话说,哪一个得到了红色的曲线?

如中所述,您不能在
where
子句的左侧使用不是来自当前声明的类型参数

因此,正如w0lf在另一个问题中所建议的,您可以做的是在接口(而不是方法)声明中提供这两种类型:

public class MyGenericClass<TSomeClass, TSomeInterface> {
    where TSomeClass : TSomeInterface 
    public void MyGenericMethod() // not so generic anymore :( 
    {
        //...
    }
}
可能您可以将其作为一个扩展方法,使其在用户面前看起来像一个实际的方法

这两者都不是您想要的,但可能比中间类型解决方案更好

至于为什么不呢?我猜这会使编译器变得复杂,而不会增加足够的值。这是一个例子。尽管C#和Java之间存在显著差异,但我认为她的结论也适用于此:

底线是类型下限的有用性 参数有些争议。它们会让人困惑,也许 甚至在用作泛型类的类型参数时也会产生误导。在…上 另一方面,泛型方法偶尔会从类型中获益 具有下限的参数。对于方法,为 通常会发现缺少下限类型参数。这样的 变通方法通常涉及静态泛型方法或更低的 绑定通配符


她还提供了一个很好的用例,请参见上面的链接。

扩展方法提供了最好的解决方案,尽管它不能完全解决您的所有问题

public class MyGenericClass<TSomeClass>
{
}

public static class MyGenericClassExtensions
{
    public static void MyGenericMethod<TSomeClass, TSomeInterface>(this MyGenericClass<TSomeClass> self)
        where TSomeClass : TSomeInterface
    {
        //...
    }
}
如果声明的类型参数
MyGenericClass
MyGenericMethod
的第一个类型参数不匹配,则将是编译错误


由于第一个类型参数可以通过
this
参数推断,因此编译器通常可以推断这两个类型参数,如果它们对方法有附加参数。

这实际上是不可能的,因为您试图将泛型与运行时混合。不,我不是。我只是尝试应用一个C语言不允许的泛型约束(约束类型参数,使其成为包含类中类型参数的超类或实现接口)。在我看来,您尝试基于提供给方法的类型数据约束类泛型。如果要约束类泛型,则需要在类级别(逻辑上)执行此操作,否则JIT编译器无法创建具体的类。我正在尝试约束方法的参数,但我正在从正常顺序向后执行此操作。与其继承或实现
TSomeClass
,我希望它被限制在
TSomeClass
的基类和实现接口集合中。啊,我现在明白了,很抱歉:)在我的理想世界中,它当然是方法调用,就像您尝试这样做一样:
varx=newlist();s、 增加(5)。编译器假定声明正确,并且方法调用使用的参数无效+不过,我还是想了解一下语法。
static void Main(string[] args) {
    var inst = new MyGenericClass<Class1>();
    inst.MyGenericMethod<Class2>();
}
public class MyGenericClass<TSomeClass, TSomeInterface> {
    where TSomeClass : TSomeInterface 
    public void MyGenericMethod() // not so generic anymore :( 
    {
        //...
    }
}
public class MyGenericClass<TSomeClass> {
    public static void MyGenericMethod<TSomeClass, TSomeInterface>
                                         (MyGenericClass<TSomeClass> that) 
        where TSomeClass : TSomeInterface 
    {
        // use "that" instead of this
    }
}
public class MyGenericClass<TSomeClass>
{
}

public static class MyGenericClassExtensions
{
    public static void MyGenericMethod<TSomeClass, TSomeInterface>(this MyGenericClass<TSomeClass> self)
        where TSomeClass : TSomeInterface
    {
        //...
    }
}
var myGenericInstance = new MyGenericClass<TSomeClass>();
myGenericInstance.MyGenericMethod<TSomeClass, TSomeInterface>();