覆盖可变函数

Override variadic function

我无法覆盖可变函数。例子胜于雄辩,让我们举个例子:

这是我的摘要class:

public abstract class MyClass<T> {
    public abstract T DoSomething(params Object[] objs);
    public void ShowSomething(List<T> items){
        foreach(T it in items){
            Console.WriteLine(string.Format("{0},{1},{2}",it.propA,it.propB,it.propC));
        }
    }
    // Other things 
}

这是我试图覆盖它的尝试:

public class MyOverridenClass : MyClass<MyType> {
    public override MyType DoSomething(int a, int b, string c){
        return new MyType(){ propA = a+b, propB = a-b, propC = c+""+a};
     }
}

从我的主要 :

public static void Main(string[] args){
    MyOverridenClass cl = new MyOverridenClass();
    List<MyType> lst = new List<MyType>();
    lst.Add(cl.DoSomething(1,2,"foo"));
    cl.ShowSomething();
}

我希望它输出:

3,-1,foo1

但是当我编译时,我有一个错误说没有找到合适的方法来覆盖 DoSomething(int, int, string)。

是否有可能,或者我是否必须找到解决方法?

谢谢!

重写方法时,签名必须相同。你不能"invent"一个新的签名。

public override MyType DoSomething(params Object[] objs)
{
    // do something
}

在这里你无能为力...

所以你必须决定你想要你的方法有什么签名,并使用它。您甚至可以将两个签名都保留在 MyClass<T>

DoSomething in MyOverriddenClass 不能覆盖 DoSomething(params Object[] objs) 因为你不能用非可变参数覆盖可变参数函数。

为什么不这样做的简单答案是因为规范是这样说的。但是在非 C# 的想象语言中,这仍然行不通,因为实现方法不如基方法具体,违反了约定。

在 C# 中,覆盖时签名必须完全匹配,但这不是正确性所必需的。为了正确性,一个方法实现契约就足够了。

例如,这是一个基 class,return 是一个 Base 类型的东西,并以一个对象作为参数。

public class Base {
  public Base example(TParam obj)
}

如果我们要覆盖示例,我们需要它更具体才能正确

public class Derived : Base { 
  override public TReturn example(TParam2 obj) //this is illegal in C#
}

C# 要求 TReturn == BaseTParam == TParam2。同时,正确性要求不那么严格。它只需要TReturn : BaseTParam : TParam2(注意它们是翻转的)

举个例子看看为什么

Base b = new Derived()
Base newbase = d.example(default(TParam))

它必须 return 一个在 Base 中 "fit" 的值。它也最多接受可以提供给 Base.example 的任何参数。如果它需要更具体的参数,那么你就被淘汰了,因为编译器不知道(并且不能知道并且不应该知道)b是输入 Derived.

现在回到可变参数方法。可以想象,某些不是 C# 但看起来有点像的语言确实允许这样做。可以想象,这种不是 C# 的语言具有一些语法糖来分解可变参数方法,并且可以来回转换以下内容:

public T Example(params object[] objs)

public T Example2(object obj1, object obj2)

但是派生类型中的实现在其参数列表中应该始终不那么具体,而不是更具体。因此,这种(非 C#)语言所能做的最好的事情就是允许您覆盖,例如,

public T Example(params SpecificType[] values)

public T Example(params object[] objs)

public T Example2(object obj1, object obj2)

但绝不会反过来。

tl;博士:

语言不允许,也不允许这样做,因为它会破坏替换原则。