【问题标题】:Which overloaded methods are added to the delegate?哪些重载方法被添加到委托中?
【发布时间】:2013-11-23 18:38:59
【问题描述】:

以下是我在一次测试中看到的一个问题,它提出了一些问题:

给定以下代码:

public delegate B func(B b);

public class A
{
    public func x;
    public int i = 2;
    public A(int i) { this.i = i; x += f; }
    public virtual C f(A a) { Console.WriteLine("C A.f(A)"); return new C(1); }
    public virtual A f(C c) { Console.WriteLine("A A.f(C)"); return new A(2); }
}

public class B: A{
    public B(int i) : base(i) { x += f; }
    public virtual B f(B b) { Console.WriteLine("B B.f(B)"); return new B(3); }
    public new C f(A a) { Console.WriteLine("C B.f(A)"); return new C(4); } 
}

public class C: B{
    public C(int i) : base(i) { x += f; }
    public new B f(B b) { Console.WriteLine("B C.f(B)"); return new C(5); }
    public override A f(C c) { Console.WriteLine("A C.f(C)"); return new A(6); }
}

有以下主要内容:

static void Main(string[] args)
{
    C c = new C(12);
    A a = c.x(c);
    Console.WriteLine(a.i);
}
  1. 输出是什么?
  2. 如果我们将委托定义更改为:public delegate C func(B b);,会发生什么情况
  3. 当我们将委托定义更改为 public delegate T func<T,U>(U u); 并将 A 中的 x 更改为 public func<B,B> x; 时会发生什么?

官方的回答是:

到#1:

C A.f(A)
B B.f(B)
B C.f(B)
5

到#2:

它不会编译,因为在 B 类和 C 类中添加到 x 的方法是根据参数的静态类型选择的。所以在B类中需要添加B B.f(B)但返回类型不匹配,在C类中需要添加B C.f(B)但返回类型不匹配。

到#3:

它打印出与 #1 相同的答案,因为这两个定义是等价的。

这是我不明白的:

  1. 如何从所有重载选项中选择在x+=f; 行中添加到x 的方法?具有与“this”的动态类型“最接近”的参数类型的重载方法是否被选中?
  2. 除非用inout 声明,否则泛型委托不是非变体吗?第 3 点的答案有何意义?

【问题讨论】:

    标签: c# generics delegates covariance contravariance


    【解决方案1】:

    是否选择了与动态类型“this”具有“最接近”参数类型的重载方法?

    没有。如果这是真的,那么所有构造函数都会选择相同的方法 (B C.f(B)),因为它完全匹配并且是最派生的类型。而是使用thisstatic 类型。

    这意味着:

    1. A 中,选择了C A.f(A),因为它是A 上唯一与func 匹配的方法。
    2. B 中,选择了B B.f(B),因为它是B 上唯一完美匹配的方法。
    3. C 中,选择了B C.f(B),因为它完美匹配并且声明为比B B.f(B) 更派生的类型。

    除非用inout 声明,否则泛型委托不是非变体吗?

    是的,这样的委托是不变的,这意味着您不能将func<B, B> 转换为func<A, B>func<B, C>func<A, C>。但它不会改变从方法组到委托的转换规则,无论委托类型是否为泛型,都允许进行类似的转换。

    【讨论】:

    • 那么哪些方法被添加到了委托中呢?如果我添加到 A 类 public virtual C f(B b) { Console.WriteLine("C A.f(B)"); return new C(2); },那么它将被添加而不是 C A.f(A)。请注意,它现在有 2 个委托类型的方法,并且新的方法与静态类型不匹配。这是为什么呢?
    • @Shookie 因为它比C f(A a) 更匹配。从C f(A a)B func(B b),您必须进行两项更改。从C f(B b),只有一个变化。
    • 值得注意的是,即使使用inout 装饰声明的委托也无法在涉及Delegate.Combine 的场景中支持协变或逆变。
    • @supercat 你什么意思?以下代码对我来说很好用:Func<string> fs1 = () => "a"; Func<string> fs2 = () => "b"; Func<object> fo = fs1 + fs2; fo().Dump();。这不是你的意思吗?
    • 他的意思是这样的:Action<ICloneable> a1 = x => { }; Action<IConvertible> a2 = x => { }; Action<string> b1 = a1; Action<string> b2 = a2; var combination = b1 + b2;。我使用了一个委托返回类型为 void 的示例,因为很少会组合返回值的委托。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多