为什么我不能声明C#方法虚拟和静态?

Luk*_*uke 50 c# oop

我有一个辅助类,它只是一堆静态方法,并且想要辅助类的子类.某些行为是独特的,具体取决于子类,所以我想从基类调用虚方法,但由于所有方法都是静态的,我无法创建普通的虚方法(需要对象引用才能访问虚方法).

有没有办法解决?我想我可以使用单例.. HelperClass.Instance.HelperMethod()并不比HelperClass.HelperMethod()差.布朗尼指出任何可以指出支持虚拟静态方法的语言的人.

编辑:好的,我疯了.谷歌搜索结果让我觉得我不是那里的.

Chr*_*org 41

虚拟静态方法没有意义.如果我打电话HelperClass.HelperMethod();,为什么我会期望调用一些随机子类'方法?当你有2个子类时,解决方案真的会崩溃HelperClass- 你会使用哪一个?

如果你想拥有可重写的静态类型方法,你可能应该使用:

  • 单例,如果您希望全局使用相同的子类.
  • 传统类层次结构,具有工厂或依赖注入,如果您希望在应用程序的不同部分中使用不同的行为.

选择在您的情况下更有意义的解决方案.

  • -1因为你忘记了泛型.T.Add(leftT,rightT); 有这么多意义.不是吗? (15认同)
  • 是的,它们确实有意义,它只是语义问题.我认为如果在类中声明静态方法是有意义的,那么允许在每个类型的基础上覆盖它是有意义的.请参阅此线程中的Delphi示例.你可能会说"静态"具有明确的含义; 好吧,在C语言中,它与C#和Java有着截然不同的含义. (10认同)
  • 您将如何覆盖子类中的实现? (3认同)
  • 是的,但是静态上下文中的基类型不能提供子类的实现,这是原始问题所要求的. (3认同)
  • @etrusco是正确的。其他语言(例如Python)具有虚拟静态方法。在这些语言中,对象可用于动态调度,但不能传递给方法(因为方法是静态的)。 (2认同)

See*_*eeR 32

我不认为你疯了.您只想使用.NET当前不可能的东西.

如果我们谈论泛型,那么您对虚拟静态方法的请求就会非常有意义.例如,我对CLR设计师的未来请求是允许我写这样的接口:

public interface ISumable<T>
{
  static T Add(T left, T right);
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

public T Aggregate<T>(T left, T right) where T : ISumable<T>
{
  return T.Add(left, right);
}
Run Code Online (Sandbox Code Playgroud)

但现在不可能,所以我这样做:

    public static class Static<T> where T : new()
    {
      public static T Value = new T();
    }

    public interface ISumable<T>
    {
      T Add(T left, T right);
    }

    public T Aggregate<T>(T left, T right) where T : ISumable<T>, new()
    {
      return Static<T>.Value.Add(left, right);
    }
Run Code Online (Sandbox Code Playgroud)

  • @SeeR:如果有问题的类型满足`new`约束,你的方法就可以了.静态虚方法允许这种结构以类型安全的方式使用,其类型不满足`new`约束.或者,可以让`Static`类没有`new`约束,而是尝试使用Reflection来创建一个带有特殊参数化构造函数的对象.不幸的是,我不知道如何使这种类型安全. (4认同)
  • @John Saunders:他想要静态虚拟方法,但这是不可能的 - 他必须使用实例方法.他也不想每次想要使用这个静态(现在实例)方法时实例化这个类 - 这就是我创建Static <T>类的原因.现在他只有一个类的实例用于整个应用程序.我认为这种功能可以接受.Aggregate <T>方法只是他如何使用它的一个例子.总而言之,我们在c#中有静态虚拟替换 - 这不是有问题的请求吗? (3认同)

Ala*_*lan 15

实际上,这可以在Delphi中完成.一个例子:

type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  end;

  TTestClass = class
  public
    class procedure TestMethod(); virtual;
  end;

  TTestDerivedClass = class(TTestClass)
  public
    class procedure TestMethod(); override;
  end;

  TTestMetaClass = class of TTestClass;

var
  Form1: TForm1;

implementation

{$R *.dfm}

class procedure TTestClass.TestMethod();
begin
  Application.MessageBox('base', 'Message');
end;

class procedure TTestDerivedClass.TestMethod();
begin
  Application.MessageBox('descendant', 'Message');
end;


procedure TForm1.FormShow(Sender: TObject);
var
  sample: TTestMetaClass;
begin
  sample := TTestClass;
  sample.TestMethod;
  sample := TTestDerivedClass;
  sample.TestMethod;
end;
Run Code Online (Sandbox Code Playgroud)

很有趣.我不再使用Delphi,但我记得能够使用元类特征在自定义设计器画布上轻松创建不同类型的控件:控件类,例如.TButton,TTextBox等是一个参数,我可以使用实际的元类参数调用适当的构造函数.

那种穷人的工厂模式:)

  • 事实上,c#不支持静态虚拟方法让我发疯...特别认为c#是由10年前设计delphi的同一个人设计的(Anders Hejlsberg) (7认同)

Dav*_*vy8 12

只需使用常规静态方法然后使用new关键字对其进行遮蔽即可达到相同的效果

public class Base 
{
    //Other stuff

    public static void DoSomething()
    {
        Console.WriteLine("Base");
    }
}

public class SomeClass : Base
{
    public new static void DoSomething()
    {
        Console.WriteLine("SomeClass");
    }
}
public class SomeOtherClass : Base
{
}
Run Code Online (Sandbox Code Playgroud)

然后你可以调用这样的方法

Base.DoSomething(); //Base
SomeClass.DoSomething(); //SomeClass
SomeOtherClass.DoSomething(); //Base
Run Code Online (Sandbox Code Playgroud)

  • 这可能会产生意想不到的后果.例如,如果你的基类中有另一个调用DoSomething的方法,并且你调用SomeClass.ThatOtherMethod(),那么该方法会调用base的DoSomething,而不是SomeClass的版本.https://dotnetfiddle.net/scRWKD (6认同)
  • 在基类中抛出 NotImplementedException 以确保没有调用 this (2认同)

小智 8

我来自Delphi,这是我在c#中非常想念的很多功能.Delphi允许您创建类型化类型引用,并且您可以在需要父类类型的任何地方传递派生类的类型.这种对象类型的处理具有强大的实用性.特别是允许运行时确定元数据.我在这里混合语法非常糟糕,但在c#中它看起来像:

    class Root {
       public static virtual string TestMethod() {return "Root"; }
    }
    TRootClass = class of TRoot; // Here is the typed type declaration

    class Derived : Root {
       public static overide string TestMethod(){ return "derived"; }
    }

   class Test {
        public static string Run(){
           TRootClass rc;
           rc = Root;
           Test(rc);
           rc = Derived();
           Test(rc);
        }
        public static Test(TRootClass AClass){
           string str = AClass.TestMethod();
           Console.WriteLine(str);
        }
    } 
Run Code Online (Sandbox Code Playgroud)

会产生:根源


Pet*_*ker 7

静态方法存在于类的实例之外.它不能使用任何非静态数据.

虚拟方法将被重载函数"覆盖",具体取决于实例的类型.

所以你在静态和虚拟之间有明显的矛盾.

这不是支持问题,而是一个概念.

更新:我在这里被证明是错的(见评论):

所以我怀疑你会发现任何支持虚拟静态方法的OOP语言.

  • 不,没有矛盾,完全是编译器支持的问题,像Python这样的许多语言都可以.他们通过拥有一流的课程来实现这一目标.也就是说,这些类本身就是可以分配给变量并调用其方法的对象.(搜索"classmethod"以了解更多信息.) (10认同)
  • 可以在实例的类型上覆盖虚方法.所有子类都可以共享重载函数的相同实现.这就是为什么你想让它们成为静态和虚拟的原因.这是晚期的静态绑定,可在PHP5中使用. (3认同)
  • Object Pascal(Delphi 和开源 Lazarus 等价物)始终支持它们 (2认同)

Ale*_*ein 6

你并不疯狂.你所指的叫做Late Static Binding; 它最近被添加到PHP.有一个伟大的线程描述它 - 这里:你什么时候需要使用后期静态绑定?