35

为什么静态虚拟是不可能的?是 C# 依赖还是在 OO 世界中没有任何意义?

我知道这个概念已经被强调了,但我没有找到上一个问题的简单答案。

4

9 回答 9

52

virtual表示将在运行时选择调用的方法,具体取决于对象的动态类型。static表示不需要任何对象来调用该方法。

你建议如何以相同的方法来做这两者?

于 2009-08-07T09:35:00.643 回答
23

Eric Lippert 有一篇关于此的博客文章,并且像往常一样在他的文章中,他非常深入地涵盖了这个主题:

https://docs.microsoft.com/en-us/archive/blogs/ericlippert/calling-static-methods-on-type-parameters-is-illegal-part-one

“虚拟”和“静态”是对立的!“virtual”表示“根据运行时类型信息确定要调用的方法”,“static”表示“仅根据编译时静态分析确定要调用的方法”</p>

于 2009-08-07T12:25:17.147 回答
10

“静态”与“虚拟”的矛盾只是C#的问题。如果“静态”被“类级别”取代,就像在许多其他语言中一样,没有人会被蒙住眼睛。

太糟糕了,单词的选择使 C# 在这方面瘫痪了。仍然可以调用 Type.InvokeMember 方法来模拟对类级别的虚拟方法的调用。您只需将方法名称作为字符串传递。没有编译时检查,没有强类型,也没有控制子类实现该方法。

一些德尔福美女:

type
  TFormClass = class of TForm;
var
  formClass: TFormClass;
  myForm: TForm;
begin
  ...
  formClass = GetAnyFormClassYouWouldLike;
  myForm = formClass.Create(nil);
  myForm.Show;
end
于 2011-09-13T16:40:02.487 回答
9

那些说静态虚拟方法没有意义的人——如果你不明白这怎么可能,那并不意味着它是不可能的。有些语言允许这样做!以德尔福为例。

于 2011-12-12T10:29:59.750 回答
5

我会成为那个反对的人。您所描述的内容在技术上不是该语言的一部分。对不起。但是可以在语言中模拟它。

让我们考虑一下您的要求 - 您想要一组不附加到任何特定对象的方法,这些方法都可以在运行时或编译时轻松调用和替换。

对我来说,这听起来像是你真正想要的是一个带有委托方法的单例对象。

让我们一起举个例子:

public interface ICurrencyWriter {
    string Write(int i);
    string Write(float f);
}

public class DelegatedCurrencyWriter : ICurrencyWriter {
    public DelegatedCurrencyWriter()
    {
        IntWriter = i => i.ToString();
        FloatWriter = f => f.ToString();
    }
    public string Write(int i) { return IntWriter(i); }
    public string Write(float f) { return FloatWriter(f); }
    public Func<int, string> IntWriter { get; set; }
    public Func<float, string> FloatWriter { get; set; }
}

public class SingletonCurrencyWriter {
    public static DelegatedCurrencyWriter Writer {
        get {
            if (_writer == null)
               _writer = new DelegatedCurrencyWriter();
            return _writer;
        }
    }
}

正在使用:

Console.WriteLine(SingletonCurrencyWriter.Writer.Write(400.0f); // 400.0

SingletonCurrencyWriter.Writer.FloatWriter = f => String.Format("{0} bucks and {1} little pennies.", (int)f, (int)(f * 100));

Console.WriteLine(SingletonCurrencyWriter.Writer.Write(400.0f); // 400 bucks and 0 little pennies

鉴于这一切,我们现在有一个写出货币值的单例类,我可以改变它的行为。我基本上在编译时定义了行为约定,现在可以在编译时(在构造函数中)或运行时更改行为,也就是说,我相信你想要得到的效果。如果你想继承行为,你可以通过实现反向链接来做到这一点(即,让新方法调用前一个方法)。

也就是说,我并不特别推荐上面的示例代码。一方面,它不是线程安全的,而且真的没有很多东西可以让生活保持清醒。全球对这种结构的依赖意味着全球不稳定。这是在 C 的昏暗时期实现可变行为的众多方式之一:函数指针的结构,在这种情况下是单个全局结构。

于 2009-08-07T12:49:48.997 回答
3

对的,这是可能的。

最想要的用例是拥有可以“覆盖”的工厂

为此,您将不得不依赖使用F 有界多态性的泛型类型参数。

示例 1 我们以工厂为例:

class A: { public static A Create(int number) { return ... ;} }
class B: A { /* How to override the static Create method to return B? */}

您还希望createB可访问并返回 B 类中的 B 对象。或者您可能希望 A 的静态函数成为 B 可以扩展的库。解决方案:

class A<T> where T: A<T> { public static T Create(int number) { return ...; } }
class B: A<B>  { /* no create function */ }
B theb = B.Create(2);       // Perfectly fine.
A thea = A.Create(0);       // Here as well

示例 2(高级): 让我们定义一个静态函数来将值矩阵相乘。

public abstract class Value<T> where T : Value<T> {
  //This method is static but by subclassing T we can use virtual methods.
  public static Matrix<T> MultiplyMatrix(Matrix<T> m1, Matrix<T> m2) {
    return // Code to multiply two matrices using add and multiply;
  }
  public abstract T multiply(T other);
  public abstract T add(T other);
  public abstract T opposed();
  public T minus(T other) {
    return this.add(other.opposed());
  }
}
// Abstract override
public abstract class Number<T> : Value<T> where T: Number<T> {
  protected double real;

  /// Note: The use of MultiplyMatrix returns a Matrix of Number here.
  public Matrix<T> timesVector(List<T> vector) {
    return MultiplyMatrix(new Matrix<T>() {this as T}, new Matrix<T>(vector));
  }
}
public class ComplexNumber : Number<ComplexNumber> {
  protected double imag;
  /// Note: The use of MultiplyMatrix returns a Matrix of ComplexNumber here.
}

现在您也可以使用静态MultiplyMatrix方法直接从 ComplexNumber 返回一个复数矩阵

Matrix<ComplexNumber> result = ComplexNumber.MultiplyMatrix(matrix1, matrix2);
于 2014-12-15T16:10:58.897 回答
2

虽然从技术上讲,不可能定义静态虚拟方法,但由于此处已经指出的所有原因,您可以在功能上完成我认为您正在尝试使用 C# 扩展方法的功能。

从微软文档:

扩展方法使您能够将方法“添加”到现有类型,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。

查看扩展方法(C# 编程指南)了解更多详细信息。

于 2009-08-07T12:35:27.697 回答
1

在 .NET 中,虚拟方法分派(大致)是通过在运行时调用方法时查看对象的实际类型并从类的 vtable 中找到最重写的方法来完成的。调用静态类时,没有要检查的对象实例,因此没有要查找的 vtable。

于 2009-08-07T12:20:13.310 回答
0

总结所有提供的选项:

于 2015-02-10T17:49:39.717 回答