Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
482 views
in Technique[技术] by (71.8m points)

c# - 实例化抽象基类的静态方法中的几个派生类(取决于参数)中的任何一个(Instantiate any one of several derived classes (depending on an argument) within a static method of the abstract base class)

I have been trying to find an elegant way to avoid repeating code in all of my derived classes.

(我一直在尝试寻找一种优雅的方法来避免在所有派生类中重复代码。)

At this point, I am unsure as to the best way to proceed.

(在这一点上,我不确定最好的处理方法。)

I'd like to write a single method in the base class that will instantiate and use any of its derived classes without having to edit the method when I write new derived classes.

(我想在基类中编写一个方法,该方法将实例化和使用其任何派生类,而在编写新的派生类时不必编辑该方法。)

I have tried learning/using a generic method but started to think I might be heading down a dead end for this application.

(我尝试学习/使用通用方法,但开始认为我可能会为此应用程序陷入困境。)

I understand that using reflection can be expensive, and since this method is meant to handle hundreds or even thousands of Elements, it seemed like a bad idea.

(我知道使用反射可能会很昂贵,并且由于此方法旨在处理成百上千个Element,因此似乎是个坏主意。)

Now I'm thinking of trying to pass in the class itself as an argument somehow... maybe.

(现在我正在考虑尝试以某种方式将类本身作为参数传递……也许。)

That doesn't seem quite right to me either.

(对我来说,这也不是很正确。)

I'm willing to do the research, but would love any help pointing me in the right direction.

(我愿意进行研究,但是很乐意为我指明正确的方向。)

Here is an abridged version of what I have...

(这是我所拥有的简要版本...)

Base Class:

(基类:)

public abstract class Element
{
    public string ElementName { get; }
    public List<string> BadParameters { get; set; } = new List<string>();

    //Constructor
    public Element(string name)
    {
        ElementName = name;
    }

    //The method in question---
    public static List<string> GetBadParameters(//derived class to instantiate)
    {
        var elem = new //derived class();
        return elem.BadParameters;
    }

}

Derived Class 1:

(派生类1:)

public class Wall : Element
{
    public double Length { get; set; }
    public bool LoadBearing { get; set; }

    //Constructor
    public Wall(string name): base(name)
    {
        SetBadParameters();
    }

    public void SetBadParameters()
    {
        BadParameters = //A wall specific way of setting bad parameters
    }
}

Derived Class 2:

(派生类2:)

public class Floor : Element
{
    public double Area { get; set; }
    public double Slope { get; set; }

    //Constructor
    public Floor(string name): base(name)
    {
        SetBadParameters();
    }

    public void SetBadParameters()
    {
        BadParameters = //A floor specific way of setting bad parameters
    }
}

Implementation:

(实现方式:)

public class Implementation
{
    public List<string> GetAllBadElementParameters()
    {
        List<string> output = new List<string>;

        List<string> badWalls = GetBadParameters(//Wall class)
        List<string> badFloors = GetBadParameters(//Floor class)

        output = output.AddRange(badWalls).AddRange(badFloors);
        return output;
    }
}

EDIT - To clarify:

(编辑-要澄清:)

The actual content of

(实际内容)

public List<string> BadParameters

does not matter.

(没关系。)

Bad parameters, how and why they are bad, are inconsequential.

(不好的参数,如何以及为什么不好是无关紧要的。)

What I'm trying to accomplish is avoid having the method "GetBadParameters()" defined in the derived class, since this method will be the exact same for all derived classes.

(我要完成的工作是避免在派生类中定义方法“ GetBadParameters()”,因为该方法对于所有派生类都是完全相同的。)

It is only the populating of the "BadParameter" base class property that changes from one derived class to another.

(只是从一个派生类到另一个派生类的“ BadParameter”基类属性的填充。)

EDIT 2 - My attempt at a generic method in the base class:

(编辑2-我在基类中的通用方法的尝试:)

I know this won't work, but it may convey what I'd like to have happen.

(我知道这行不通,但可以传达我想发生的事情。)

    public static List<string> GetAllBadParameters<T>(List<string> names) where T : ANY DERIVED CLASS, new()
    {
        List<string> output = new List<string>();

        foreach (string name in names)
        {
            var elem = new T(name);
            foreach (string badParameter in elem.BadParameters)
            { 
                output.Add(badParameter); 
            }
        }

        return output;
    }
  ask by Leetheus translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Well … First of all, I am guessing that by "bad parameter" you mean the name of a property in an Element-derived class.

(好吧……首先,我猜想“坏参数”是指元素派生类中的属性名称。)

For example I'm guessing that if the Length of a Wall is negative then "Length" would be a bad parameter of that particular Wall.

(例如,我猜测如果墙壁的长度为负数,则“长度”将是该特定墙壁的错误参数。)

Secondly I'm guessing that you are going to have a largish number of elements, eg a number of walls and floors (and other things) in a diagram or whatever.

(其次,我猜测您将拥有大量的元素,例如,图中的墙壁和地板(以及其他东西)的数量等等。)

Assuming that, then one way to do this would be to have an abstract method in the Element class that returns the bad parameters, and implement it in each derived class.

(假设这样做的一种方法是在Element类中有一个抽象方法,该方法返回错误的参数,并在每个派生类中实现它。)

Something like this:

(像这样:)

public abstract class Element  
{
    public string Name { get; private set; }
    public abstract IList<string> GetBadParameters();
    public Element( string name) { this.Name = name; }
}

public class Wall 
{
    public Wall( string name): base(name) {}
    public double Length { get; set; }
    public bool IsLoadBearing { get; set; }

    public IList<string> GetBadParameters() {
         List<string> bad = new List<string>();
         if (this.Length <= 0) { bad.Add( this.Name + ": " + nameof( this.Length); }
         if (this.IsLoadBearing && this.Length > whatever) { bad.Add( this.Name + ": " + nameof( this.IsLoadBearing); }
         return bad;
    }
}

Then if you had a list of all the elements you could get all the bad parameters by

(然后,如果您拥有所有元素的列表,则可以通过以下方式获取所有错误参数:)

IList<string> allBadParemeters = elements.SelectMany( e => e.GetBadParameters() ); 

What I would say though is that this might not be such a great design.

(我要说的是,这可能不是一个很好的设计。)

You would end up with a system in which a lot of elements contain bad parameters.

(您将最终得到一个其中许多元素包含错误参数的系统。)

Life could be a lot easier if you just prevent bad parameters from happening in the first place.

(如果您只是从头开始防止不良参数的发生,那么生活可能会容易得多。)

You can do this by making the 'set' methods of all the parameter properties private and adding a method such as bool Wall.TrySetParameters( double length, bool isLoadBearing).

(您可以通过将所有参数属性的'set'方法设为私有并添加诸如bool Wall.TrySetParameters(double length,bool isLoadBearing)之类的方法来实现。)

If the parameters are bad then this would just return false and not assign the parameters to the wall.

(如果参数很差,则只会返回false而不将参数分配给墙。)

If you want to have TrySetParameters in the base class then you could do it with a more general signature such as

(如果要在基类中包含TrySetParameters,则可以使用更通用的签名来实现,例如)

 public struct Parameter { 
     public Parameter( string name, object value) { … } 
     public string Name { get; private set; }
     public object Value { get; private set; }
 }

 abstract public class Element { 
    …
    abstract public bool TrySetParameters( params Parameter[] parameters); 
 }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...