为什么静态虚拟不可能? C#是依赖还是在OO世界中没有任何意义?
我知道这个概念已被强调,但我没有找到上一个问题的简单答案。
答案 0 :(得分:51)
virtual
表示将在运行时选择调用的方法,具体取决于对象的动态类型。 static
表示不需要对象来调用该方法。
你怎么建议用同样的方法做两件事?
答案 1 :(得分:21)
Eric Lippert有一篇关于此事的博客文章,和他的帖子一样,他深入探讨了这个主题:
“虚拟”和“静态”是对立的! “virtual”表示“根据运行时类型信息确定要调用的方法”,“static”表示“根据编译时静态分析确定要调用的方法”
答案 2 :(得分:7)
“静态”和“虚拟”之间的矛盾只是一个c#问题。如果“静态”被“班级”取代,就像许多其他语言一样,没有人会被蒙住眼睛。
在这方面,c#的选择太糟糕了c#瘫痪了。仍然可以调用Type.InvokeMember方法来模拟对类级别虚拟方法的调用。您只需将方法名称作为字符串传递。没有编译时检查,没有强类型,也没有子类实现该方法的控制。
一些德尔福美女:type
TFormClass = class of TForm;
var
formClass: TFormClass;
myForm: TForm;
begin
...
formClass = GetAnyFormClassYouWouldLike;
myForm = formClass.Create(nil);
myForm.Show;
end
答案 3 :(得分:7)
那些说静态虚拟方法没有意义的人。如果你不明白这是怎么可能的,那并不意味着它是不可能的。有语言允许这个!!比如说Delphi。
答案 4 :(得分: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的昏暗黑暗时期实现可变行为的众多方法之一:函数指针的结构,在这种情况下是单个全局结构。
答案 5 :(得分:2)
虽然从技术上来说无法定义静态虚拟方法,但由于此处已经指出的所有原因,您可以在功能上完成我认为您尝试使用C#扩展方法。
来自MSDN:
扩展方法可让您“添加” 没有的现有类型的方法 创建一个新的派生类型, 重新编译或以其他方式修改 原始类型。
答案 6 :(得分:2)
是的,这是可能的。
最需要的用例是让工厂可以“覆盖”
为此,您必须使用F-bounded polymorphism依赖泛型类型参数。
示例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);
答案 7 :(得分:1)
在.NET中,通过在运行时调用方法时查看对象的实际类型(并从类的vtable中查找最重要的方法)来(粗略地)完成虚方法调度。在调用静态类时,没有要检查的对象实例,因此没有vtable可以进行查找。
答案 8 :(得分:0)
总结所有选项:
这不是C#的一部分,因为在它中,static
means "not bound to anything at runtime"就像C(也许更早)一样。 static
个实体 绑定到声明类型(因此能够访问其他static
实体),但仅限于编译时。
static
equivalent (if needed at all) means "bound to a type object at runtime"代替。示例包括Delphi,Python,PHP。这可以通过多种方式进行模拟,可归类为: