通用方法分配给委托

14

我对委托和泛型方法有些困惑。

是否可以将一个带有泛型类型参数的方法分配给一个委托?

例如:

//This doesn't allow me to pass a generic parameter with the delegate.
public delegate void GenericDelegate<T>() 

someDelegate = GenericMethod;
public void GenericMethod<T>() where T : ISomeClass
{

}

我正在尝试使用一个泛型类型的接口将此委托传递到期望该方法的接口中,使用以下函数:

void CheckDelegate(GenericDelegate<ISomeClass> mechanism);

这样我就可以像这样使用委托:

someDelegate<ImplementsSomeClass>();

someDelegate是什么样子?(你得到了什么错误?) - Kirk Woll
公共委托 void GenericDelegate<in T>(); - 10001110101
变量“someDelegate”不能与类型参数一起使用。 - 10001110101
дҪ зҡ„еҮҪж•°CheckDelegateжҳҜе®ҡд№үдёәvoid CheckDelegate(SomeDelegate<ISomeClass> mechanism){}иҝҳжҳҜvoid CheckDelegate(GenericDelegate<ISomeClass> mechanism){}пјҹиҝҷдёӨдёӘе®Ңе…ЁдёҚеҗҢгҖӮ - YK1
1
为什么不直接使用参数类型为ISomeState的委托? - FLCL
显示剩余7条评论
4个回答

10

你的问题没有意义,因为你永远不能使用开放式泛型类型来声明存储位置(比如局部变量或字段)。它必须始终是封闭的。

我理解你想要将一个 GenericDelegate<T> 传递给一个接受这样的值作为参数的方法。但即使是这样,委托类型也会使用 T 作为泛型类型参数而变成封闭式的。

在你的示例代码中,你写道:

someDelegate = GenericMethod;

但是someDelegate应该具有什么类型呢?它必须要么显式地关闭(GenericDelegate<string>),要么使用外部范围的泛型类型参数进行关闭:

void SomeOuterMethod<T>() where T : ISomeClass {
    GenericDelegate<T> someDelegate = GenericMethod<T>;
}

我希望我已经理解了您的问题。如果没有,请澄清一下。如果您能详细说明您想要实现什么,我会尝试提供一个实用的解决方案。
像Haskell这样的其他语言确实支持传递开放式通用类型的值(也就是说,您可以有一个类型为IEnumerable<>的变量)。这是实现monad所必需的。CLR没有这个功能。
新想法:您可以创建一个非泛型基类型,并在其中创建一个可以被覆盖的泛型方法,而不是委托:
interface CheckHandler {
 public void Check<T>(T someArg);
}

希望这能满足你的需求。你不能自由地传递任何CheckHandler。它的Check方法可以使用任意类型参数进行调用。

我正在尝试修改一个对象的状态。类型T将指定对象需要转换到的状态。 - 10001110101
为什么委托不能被称为someDelegate<ClassThatImplementsSomeClass>();的解释很好。我完全同意。 - helb
所以这是不可能的,因为当我将类型转换为<ISomeClass>时,它会变成封闭状态,对吗? - 10001110101
1
我认为是这样的。如果你想保持泛型,你必须在所有方法(或它们周围的类型)中添加泛型类型参数,以便你有能力将实际的泛型类型参数流传到涉及的所有代码中。我在答案中添加了一个新的想法。那有帮助吗? - usr
@usr:听起来像是我想的一样[请看我的回答] - supercat

3

有可能需要一个单独的“东西”来处理多个参数类型,但是Delegate类并不适用于此。相反,您需要定义一个接口。这是一个简单的例子:

public interface IMunger<TConstraint>
{
    void Munge<T>(ref T it) where T : TConstraint;
}
public class Cloner : IMunger<ICloneable>
{
    public void Munge<T>(ref T it) where T : ICloneable
    {
        if (typeof(T).IsValueType) // See text
            return;
        it = (T)(it.Clone());
    }
}

即使系统有一个预定义的带有引用参数的委托类型(例如,ActByRef<ICloneable> 将具有签名 void Invoke(ref ICloneable p1)),这样的委托只能用于精确类型为ICloneable的变量,而不是其他实现了ICloneable接口的存储位置类型。相比之下,一个非泛型类类型Cloner的单个对象能够提供适用于任何实现ICloneable的存储位置类型的方法。请注意,如果该方法被传递一个指向包装值类型实例的引用,它将用一个实例的副本替换它,但如果它被传递一个值类型变量的引用,它将保持原样(除非值类型将其状态保存在可变类对象中,并持有对其的引用--这是一种非常危险的模式--说StructType foo = (StructType)(bar.Clone());等效于foo = bar;结构类型可能想要实现ICloneable以允许它参与深度克隆层次结构,但这并不意味着它的Clone方法需要做任何事情。

2

更新示例以支持将方法作为参数,仅演示如何将通用委托作为其他方法的参数调用。

class Program
{
    public delegate T Transformer<T>(T arg) where T : IComparable;

    public static void Transform<T>(T value, Transformer<T> method) where T: IComparable
    {
        Console.WriteLine(method(value));
    }

    static void Main(string[] args)
    {
        Transform(5, Square);
    }

    static int Square(int x)
    {
        return x * x;
    }
}

0

我尝试了以下内容:

public class Test
{
    public interface ISomeClass { }

    public class ImplementsSomeClass : ISomeClass { }

    public delegate void GenericDelegate<T>() where T : ISomeClass;

    public void GenericMethod<T>() 
    {
        // EDIT: returns typeof(ImplementsSomeClass)
        var t = typeof(T); 
    }

    public void CheckDelegate(GenericDelegate<ISomeClass> mechanism)
    {
        // EDIT: call without generic argument since it is already determined 
        mechanism(); 
    }

    public void test()
    {
        GenericDelegate<ISomeClass> someDelegate = GenericMethod<ImplementsSomeClass>;
        CheckDelegate(someDelegate);
    }
}

而且我没有编译错误。这是运行时问题还是我误解了你的问题描述?


我想使用泛型参数调用委托。 - 10001110101
someDelegate<ClassThatImplementsSomeClass>(); - 10001110101
有没有可能不每次都创建一个委托来完成它?我正在寻求更深入的理解,为什么不能使用通用参数调用委托。委托调用someDelegate<SomeClassImplementation>();确实是我要找的。 - 10001110101
@10001110101 你不能这样做,因为传递的委托已经设置了其泛型参数,因为我们将其定义为 someDelegate = GenericMethod<ImplementsSomeClass>; 之后你不能使用不同的参数调用它。有关此问题,请参见usr的答案。 - helb

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