【问题标题】:C# "Inheriting" Static Methods?C#“继承”静态方法?
【发布时间】:2015-03-20 13:54:59
【问题描述】:

这是我想要完成的示例:

abstract class DoSomething
{
    static void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You asked the abstract class to work. Too bad.");
    }
}

class InspireMe : DoSomething
{
    static void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You are amazing.");
    }
}

class InsultMe : DoSomething
{
    static void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You aren't worth it.");
    }
}

class Program
{
    static void Main()
    {
        DoSomething worker = InsultMe;
        worker.DoWhateverItIsThatIDo(); 

        worker = InspireMe;
        worker.DoWhateverItIsThatIDo();
    }
}

我来自 Python 背景,其中方法本身可以是一个变量,然后可以调用它。看起来 C# 没有这个概念,但我正在尝试完成类似的事情。

我的想法是我想要一个可以是抽象类型的变量,以便在其中可以存在许多不同类型的子类型。所有这些亚型都有一定的方法。我希望能够将这些子类型中的任何一个分配给这个抽象类型的变量,然后调用子类型中存在的 static 方法。

在 C# 术语中,我希望能够将 class 分配给变量,而不是类的 instance,然后调用该类的静态方法。

工厂听起来可能走在正确的道路上,但我不确定工厂本身如何能够生成对的这些引用(而不是创建实例)。

我可以修改它以使用实例,但假设我想要生成每种类型的类的静态方法,所有这些仍然从基类型继承。

我觉得最有可能做到这一点 - 有人可以建议吗?

【问题讨论】:

  • 方法可以是变量,在某种意义上:stackoverflow.com/questions/6695537/…
  • Action workerMethod = InspireMe.DoWhateverItIsThatIDo; workerMethod(); 怎么样?不完全是你写的,但如果你想要一个实际的 worker 对象,你可以在其上调用多个方法,那么你不应该使用静态方法。

标签: c# inheritance static-methods


【解决方案1】:

在您所描述的意义上,您不能将类用作 C# 中的变量。反射本质上允许您将类型视为变量并动态调用它们的静态成员,但它会很混乱并且不是类型安全的。

您可以通过使用单例模式基本上完成您想要做的事情:

interface IDoSomething
{
    void DoWhateverItIsThatIDo();
}

class DoSomething : IDoSomething
{
    private DoSomething() {}
    internal static readonly IDoSomething Instance;
    static DoSomething()
    {
        Instance = new DoSomething();
    }

    public void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You asked the abstract class to work. Too bad.");
    }
}

class InspireMe : IDoSomething
{
    private InspireMe() {}
    internal static readonly IDoSomething Instance;
    static InspireMe()
    {
        Instance = new InspireMe();
    }

    public void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You are amazing.");
    }
}

class InsultMe : IDoSomething
{
    private InsultMe() {}
    internal static readonly IDoSomething Instance;
    static InsultMe()
    {
        Instance = new InsultMe();
    }

    public void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You aren't worth it.");
    }
}
class Program
{
    static void Main()
    {
        IDoSomething worker = InsultMe.Instance;
        worker.DoWhateverItIsThatIDo(); 

        worker = InspireMe.Instance;
        worker.DoWhateverItIsThatIDo();
    }
}

【讨论】:

  • 按原样,代码不会编译;您的派生类型没有要调用的基类型的构造函数(唯一的一个是私有的),因此不会编译。而且,如果您确实向它们公开了构造函数,那么这些类型将不会是单例,那么您创建多个类型的实例等等。
  • @Servy 在示例中我没有看到任何派生类,只是接口实现,所以没有编译问题。
  • @Servy 抱歉,您不得不批评我的半生不熟的代码。我现在已经验证它可以按预期编译和工作。
  • 我认为单例或静态代码根本没有任何理由。无论如何,静态代码都不好生成。不采用注射是不可能进行测试的。他似乎不懂 c# IMO... 因为所需要的只是接口,最多是一个带有虚拟方法的抽象类。
  • @phillip 看来 OP 想要一些适合某个接口的静态对象。这不是单例模式的好用例吗?代码的static 部分并没有真正做太多。只需调用一个空的构造函数并将其分配给一个字段。
【解决方案2】:

C# 和 Java 都不能让您覆盖静态基类方法。

但是,您似乎仍然在使用对对象的引用(您的 worker 变量),那么为什么不直接使用非静态类方法呢?

(如果这不是您的本意,请澄清。)

【讨论】:

    【解决方案3】:

    我不是 100% 确定这是你想要的,但我写了一个模拟 Prototypal inheritance in C# 的库。

    public class Foo: ProtoObject {}
    public class Bar: Foo {}
    
    dynamic myFoo = new Foo();
    dynamic yourFoo = new Foo();
    dynamic myBar = new Bar();
    
    myFoo.Prototype.Name = "Josh";
    myFoo.Prototype.SayHello = new Action(s => Console.WriteLine("Hello, " + s));
    
    yourFoo.SayHello(myBar.Name); // 'Hello, Josh'
    

    这当然涉及大量使用 dynamic 关键字,这可能没有用,因为您会丢失大量编译时间检查。

    【讨论】:

    • 那是一些不错的代码人...感觉非常 javascript(ish)... :D
    【解决方案4】:

    除了类和实例之外,您真正想要的是对具有特定签名的方法的引用,在您的情况下为 void ()

    虽然您不能将静态类分配给变量,但可以以类型安全的方式将方法分配给变量。在 C# 中,您通常会使用 ActionFunc 的重载,具体取决于方法签名的外观。

    为了让这更有趣,我们假设您想引用 int Foo(string, bool) 之类的东西,只需使用 Func<string,bool,int> 类型的变量并将具有此签名的任何方法分配给它。

    解决您的问题的代码大致如下所示:

    class DoSomething
    {
        static void DoWhateverItIsThatIDo()
        {
            Console.WriteLine("You asked the abstract class to work. Too bad.");
        }
    }
    
    class InspireMe
    {
        static void DoWhateverItIsThatIDo()
        {
            Console.WriteLine("You are amazing.");
        }
    }
    
    class InsultMe
    {
        static void DoWhateverItIsThatIDo()
        {
            Console.WriteLine("You aren't worth it.");
        }
    }
    
    class Program
    {
        static void Main()
        {
            Action worker = InsultMe.DoWhateverItIsThatIDo;
            worker(); 
    
            worker = InspireMe.DoWhateverItIsThatIDo;
            worker();
        }
    }
    

    【讨论】:

    • 你得到了我的投票,但问题是......我认为他希望 DoSomething.DoWhateverItIsThatIDo() 成为默认方法,如果 InspireMe 或 InsultMe 中不存在该方法就会被调用......也许我'我错了 - 我们会看到的。
    • 不编译 - InsultMeInspireMe 是类型,而不是 Actions - 应该是 Action worker = InsultMe.DoWhateverItIsThatIDo; 然后是 worker();。您可能还想为这些静态方法添加 public 修饰符。 ;)
    • 感谢 Pieter,已修复
    【解决方案5】:

    解决方法可能是在基础抽象类中声明一个Action 类型的属性,该属性包含要调用的方法。然后在派生类实例化期间通过调用基类构造函数来初始化该属性:

    abstract class DoSomething
    {
        public Action DoWhateverItIsThatIDo { get; set; }
    
        protected DoSomething() { DoWhateverItIsThatIDo = DoSomething.DoIt; }
    
        protected DoSomething(Action whatAction)
        {
            DoWhateverItIsThatIDo = whatAction;
        }
    
        protected static void DoIt()
        {
            Console.WriteLine("You asked the abstract class to work. Too bad.");
        }
    }
    
    class InspireMe : DoSomething
    {
        public InspireMe() : base(InspireMe.DoIt) { }
    
        private static void DoIt()
        {
            Console.WriteLine("You are amazing.");
        }
    }
    
    class InsultMe : DoSomething
    {
        public InsultMe() : base(InsultMe.DoIt) { }
    
        private static void DoIt()
        {
            Console.WriteLine("You aren't worth it.");
        }
    }
    
    class DoWhatBaseClassDoes : DoSomething
    {
        public DoWhatBaseClassDoes() : base() {}
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            DoSomething worker = new InsultMe();
            worker.DoWhateverItIsThatIDo();
    
            worker = new InspireMe();
            worker.DoWhateverItIsThatIDo();
    
            // In this case base class method is invoked
            worker = new DoWhatBaseClassDoes();
            worker.DoWhateverItIsThatIDo();
        }
    } 
    

    【讨论】:

    • 这似乎比它应该的麻烦多了,但我想它可以完成工作。 +1
    猜你喜欢
    • 2011-12-27
    • 2013-10-20
    • 2012-06-21
    • 1970-01-01
    • 2017-02-07
    • 2011-06-26
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    相关资源
    最近更新 更多