【问题标题】:How can I create a method whose argument is a function whose argument can be an object from any class extending a given class?如何创建一个方法,其参数是一个函数,其参数可以是扩展给定类的任何类的对象?
【发布时间】:2021-12-24 01:16:00
【问题描述】:

我有类 BC 继承自 A

public class A { }

public class B : A { }

public class C : A { }

我有一些函数将对象 BC 作为参数:

public void FunB(B obj) { }

public void FunC(C obj) { }

我想创建一个接受任何这些函数作为参数的函数。我尝试使用代表,但我没有找到解决方案。我试过这个,但我得到以下错误:

public class Test
{
    public void FunB(B obj) { }
    public void FunC(C obj) { }

    public delegate void Delegate(A obj);

    public static void Method(Delegate fun) { }

    public void Pain() 
    { 
        Delegate funB = FunB; // No overload for FunB matches the delegate Test.Delegate

        Delegate fun2 = (A obj) => { };

        fun2 += FunB; // No overload for FunB matches the delegate Test.Delegate

        Method(FunB); // Argument 1: cannot convert from 'method group' to 'Test.Delegate'
    }
}

我阅读了the documentation(这就是我尝试使用fun2 += FunB 的原因),但很明显有些东西我不明白。知道如何解决吗?

【问题讨论】:

  • FunB 的编写期望它传递的内容是至少 B 或派生自它的东西。如果您可以转换为您的委托,您就可以通过C 调用它。类型系统可以帮助您避免这个错误。
  • 差异在另一个方向起作用。如果您有 FunA(A obj),您应该能够将其分配给 Delegate(C obj),因为 该函数可以安全地处理任何 A,包括显然它必须是 C
  • 好的,现在我明白了,谢谢。我读错了方向的逆变。那么,有没有什么方法可以创建一个方法来接受带有来自父类的参数的函数呢?
  • 我相应地更改了问题的标题。我考虑过使用泛型,但它不能是any泛型,它应该是具有基类A...的对象
  • 好的,我认为像public static void Method<T>(Foo<T> fun) where T: A { } 这样的事情会奏效...

标签: c# delegates contravariance


【解决方案1】:

您可以编写这样的方法来将Action<B> 调整为Action<A>(这些天您通常应该更喜欢使用这些通用委托):

    public Action<TA> ActWithParent<TA, TB> (Action<TB> original) where TB: TA
    {
        return a =>
        {
            if(a is TB b)
            {
                original(b);
            }
        };
    }

    public void Pain()
    {

        Action<A> fun2 = ActWithParent<A, B>(FunB);
        fun2 += ActWithParent<A,C>(FunC);
    }

它可能有一个更好的名称,但请注意,如果它实际上具有匹配的类型,它只会调用“child”方法,这是您需要在调用者和被调用者之间插入的额外检查。另请注意,如果没有类型匹配,您可能希望指定不同的行为。

【讨论】:

    猜你喜欢
    • 2019-08-31
    • 1970-01-01
    • 2014-06-18
    • 2021-09-09
    • 1970-01-01
    • 2012-11-11
    • 2020-08-11
    • 2019-04-28
    • 2019-12-09
    相关资源
    最近更新 更多