C# 静态方法继承的正确替代方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1380087/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 15:52:00  来源:igfitidea点击:

What's the correct alternative to static method inheritance?

c#.netinheritancestatic

提问by Tim Coulter

I understand that static method inheritance is not supported in C#. I have also read a number of discussions (including here) in which developers claim a need for this functionality, to which the typical response is "if you need static member inheritance, there's a flaw in your design".

我知道 C# 不支持静态方法继承。我还阅读了许多讨论(包括此处),其中开发人员声称需要此功能,对此的典型回应是“如果您需要静态成员继承,则您的设计存在缺陷”。

OK, given that OOP doesn't want me to even think about static inheritance, I must conclude that my apparent need for it points to an error in my design. But, I'm stuck. I would really appreciate some help resolving this. Here's the challenge ...

好吧,鉴于 OOP 甚至不想让我考虑静态继承,我必须得出结论,我对它的明显需求指向了我设计中的一个错误。但是,我被困住了。我真的很感激一些帮助解决这个问题。这是挑战...

I want to create an abstract base class (let's call it a Fruit) that encapsulates some complex initialization code. This code cannot be placed in the constructor, since some of it will rely on virtual method calls.

我想创建一个抽象基类(我们称之为 Fruit),它封装了一些复杂的初始化代码。这段代码不能放在构造函数中,因为其中一些将依赖于虚方法调用。

Fruit will be inherited by other concrete classes (Apple, Orange), each of which must expose a standard factory method CreateInstance() to create and initialize an instance.

Fruit 将被其他具体类(Apple、Orange)继承,每个类都必须公开一个标准的工厂方法 CreateInstance() 来创建和初始化一个实例。

If static member inheritance were feasible, I would place the factory method in the base class and use a virtual method call to the derived class to obtain the type from which a concrete instance must be initialized. The client code would simple invoke Apple.CreateInstance() to obtain a fully initialized Apple instance.

如果静态成员继承可行,我会将工厂方法放在基类中,并使用对派生类的虚方法调用来获取必须从中初始化具体实例的类型。客户端代码将简单地调用 Apple.CreateInstance() 来获得一个完全初始化的 Apple 实例。

But clearly this is not possible, so can someone please explain how my design needs to change to accommodate the same functionality.

但显然这是不可能的,所以有人可以解释我的设计需要如何改变以适应相同的功能。

采纳答案by Matt Hamsmith

One idea:

一个想法:

public abstract class Fruit<T>
    where T : Fruit<T>, new()
{
    public static T CreateInstance()
    {
        T newFruit = new T();
        newFruit.Initialize();  // Calls Apple.Initialize
        return newFruit;
    }

    protected abstract void Initialize();
}

public class Apple : Fruit<Apple>
{
    protected override void Initialize() { ... }
}

And call like so:

并像这样调用:

Apple myAppleVar = Fruit<Apple>.CreateInstance();

No extra factory classes needed.

不需要额外的工厂类。

回答by Lee

I'd say the best thing to do is to create a virtual/abstract Initialise method on the fruit class which must be called and then create an external 'fruit factory' class to create instances:

我想说最好的办法是在必须调用的水果类上创建一个虚拟/抽象 Initialise 方法,然后创建一个外部“水果工厂”类来创建实例:


public class Fruit
{
    //other members...
    public abstract void Initialise();
}

public class FruitFactory()
{
    public Fruit CreateInstance()
    {
        Fruit f = //decide which fruit to create
        f.Initialise();

        return f;
    }
}

回答by Daniel Rodriguez

Why not create a factory class (templated) with a create method?

为什么不使用 create 方法创建工厂类(模板化)?

FruitFactory<Banana>.Create();

回答by Frederik Gheysels

Move the factory method out of the type, and put it in its own Factory class.

将工厂方法移出类型,并将其放入自己的工厂类中。

public abstract class Fruit
{
    protected Fruit() {}

    public abstract string Define();

}

public class Apple : Fruit
{
    public Apple() {}

    public override string Define()
    {
         return "Apple";
    }
}

public class Orange : Fruit
{
    public Orange() {}

    public override string Define()
    {
         return "Orange";
    }
}

public static class FruitFactory<T> 
{
     public static T CreateFruit<T>() where T : Fruit, new()
     {
         return new T();
     }
}

But, as I'm looking at this, there is no need to move the Create method to its own Factory class (although I think that it is preferrable -separation of concerns-), you can put it in the Fruit class:

但是,正如我所看到的,没有必要将 Create 方法移动到它自己的 Factory 类中(虽然我认为它更可取-关注点分离-),您可以将它放在 Fruit 类中:

public abstract class Fruit
{

   public abstract string Define();

   public static T CreateFruit<T>() where T : Fruit, new()
   {
        return new T();
   }

}

And, to see if it works:

并且,看看它是否有效:

    class Program
    {
        static void Main( string[] args )
        {
            Console.WriteLine (Fruit.CreateFruit<Apple> ().Define ());
            Console.WriteLine (Fruit.CreateFruit<Orange> ().Define ());

            Console.ReadLine ();
        }        
    }

回答by Bob

I would do something like this

我会做这样的事情

 public abstract class Fruit() {
      public abstract void Initialize();
 }

 public class Apple() : Fruit {
     public override void Initialize() {

     }
 }

 public class FruitFactory<T> where T : Fruit, new {
      public static <T> CreateInstance<T>() {
          T fruit = new T();
          fruit.Initialize();
          return fruit;  
      }
 } 


var fruit = FruitFactory<Apple>.CreateInstance()

回答by Noldorin

The WebRequestclass and its derivative types in the .NET BCL represent a good example of how this sort of design can be implemented relatively well.

WebRequest.NET BCL 中的类及其派生类型代表了如何相对较好地实现此类设计的一个很好的例子。

The WebRequestclass has several sub-classes, including HttpWebRequestand FtpWebReuest. Now, this WebRequestbase class is also a factory type, and exposes a static Createmethod (the instance constructors are hidden, as required by the factory pattern).

WebRequest班有几个子类,包括HttpWebRequestFtpWebReuest。现在,这个WebRequest基类也是一个工厂类型,并公开了一个静态Create方法(根据工厂模式的要求,实例构造函数是隐藏的)。

public static WebRequest Create(string requestUriString)
public static WebRequest Create(Uri requestUri)

This Createmethod returns a specific implementation of the WebRequestclass, and uses the URI (or URI string) to determine the type of object to create and return.

Create方法返回类的特定实现WebRequest,并使用 URI(或 URI 字符串)来确定要创建和返回的对象类型。

This has the end result of the following usage pattern:

这具有以下使用模式的最终结果:

var httpRequest = (HttpWebRequest)WebRequest.Create("http://stackoverflow.com/");
// or equivalently
var httpRequest = (HttpWebRequest)HttpWebWebRequest.Create("http://stackoverflow.com/");

var ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://stackoverflow.com/");
// or equivalently
var ftpRequest = (FtpWebRequest)FtpWebWebRequest.Create("ftp://stackoverflow.com/");

I personally think this is a good way to approach the issue, and it does indeed seem to be the preffered method of the .NET Framework creators.

我个人认为这是解决这个问题的好方法,而且它确实似乎是 .NET Framework 创建者的首选方法。

回答by Marcin Deptu?a

First of all, not having static initializers that can be virtual doesn't mean you can't have "standard" member methods, that could be overloaded. Second of all, you can call your virtual methods from constructors, and they will work as expected, so there's no problem here. Third of all, You can use generics to have type-safe factory.
Here's some code, that uses factory + member Initialize() method that is called by constructor (and it's protected, so you don't have to worry, that someone will call it again after creating an object):

首先,没有可以是虚拟的静态初始值设定项并不意味着您不能拥有可能被重载的“标准”成员方法。其次,你可以从构造函数调用你的虚方法,它们会按预期工作,所以这里没有问题。第三,您可以使用泛型来拥有类型安全的工厂。
这是一些代码,它使用由构造函数调用的工厂 + 成员 Initialize() 方法(并且它是受保护的,因此您不必担心,有人会在创建对象后再次调用它):


abstract class Fruit
{
    public Fruit()
    {
        Initialize();
    }

    protected virtual void Initialize()
    {
        Console.WriteLine("Fruit.Initialize");
    }
}

class Apple : Fruit
{
    public Apple()
        : base()
    { }

    protected override void Initialize()
    {
        base.Initialize();
        Console.WriteLine("Apple.Initialize");
    }

    public override string ToString()
    {
        return "Apple";
    }
}

class Orange : Fruit
{
    public Orange()
        : base()
    { }

    protected override void Initialize()
    {
        base.Initialize();
        Console.WriteLine("Orange.Initialize");
    }

    public override string ToString()
    {
        return "Orange";
    }
}

class FruitFactory
{
    public static T CreateFruit<T>() where T : Fruit, new()
    {
        return new T();
    }
}

public class Program
{

    static void Main()
    {
        Apple apple = FruitFactory.CreateFruit<Apple>();
        Console.WriteLine(apple.ToString());

        Orange orange = new Orange();
        Console.WriteLine(orange.ToString());

        Fruit appleFruit = FruitFactory.CreateFruit<Apple>();
        Console.WriteLine(appleFruit.ToString());
    }
}