如何最好地在C#中构建类heirachy以允许访问父类成员?

时间:2022-09-02 09:35:23

I am having a couple of issues deciding how best to describe a certain data structure in C# (.NET 3.5).

我有几个问题决定如何最好地描述C#(.NET 3.5)中的某个数据结构。

I have to create a class library that creates some text files for the input of a command line program. There are dozens of file types, but most of them have a similar header, footer and a couple of other properties.

我必须创建一个类库,为命令行程序的输入创建一些文本文件。有许多文件类型,但大多数都有类似的页眉,页脚和其他几个属性。

So a file might look like this:

所以文件可能如下所示:

timestamp filename company

....lots of attributes that make up the file body....

footerdetail1 footerdetail2 footerdetail3

Now out of these dozens of file types there are really only three unique header/footer combos.

现在,在这几十种文件类型中,实际上只有三种独特的页眉/页脚组合。

So I want to make a parent class that contains most of the headerItems and footeritems, and then implement the actual file types in a derived class:

所以我想创建一个包含大多数headerItems和footeritems的父类,然后在派生类中实现实际的文件类型:

class BaseFileType {

public List<HeaderItems>; 
public List<BodyItems>;   
public List<FooterItems>;
FileType filetype;
String filename;

public BaseFileType1 (FileType filetype,String filename) {

   this.filetype = filetype;
   this.filename = filename;


   // add stuff to the header list
   // add stuff to the footer list


} 

    // some methods to find items in the header/ footer lists

}

class ActualFile1 : BaseFileType {

    ActualFile() {


    //add stuff to the bodyitems list
    }


    //some other generic methods


} 

The thing is, I want to inherit the contructor from the base class for the derived class, but from what I have read this can not be done. What is the best strategy here?

问题是,我想从派生类的基类继承构造函数,但是从我读过的内容中我无法做到这一点。这里最好的策略是什么?

I have seen that I can call the base constructor from my derived class constructor like so:

我已经看到我可以从我的派生类构造函数中调用基础构造函数,如下所示:

ActualFile() : base (parent parameters)

ActualFile():base(父参数)

Is this even the best way to go about my task? In the end I am just looking for the best data structures for all of this file information so I dont need to repeat myself when I make these classes.

这甚至是完成我任务的最佳方式吗?最后,我只是在寻找所有这些文件信息的最佳数据结构,所以在制作这些类时我不需要重复自己。

What other alternatives to people thing would work? Have a single FileFactory that spits out classes containing the structure I require?

还有什么其他替代方案可以起作用?有一个FileFactory吐出包含我需要的结构的类吗?

3 个解决方案

#1


This looks like something a Template Method would solve... (Finally a place to use a pattern :)

这看起来像模板方法会解决的问题...(最后一个地方使用模式:)

public abstract class DocumentGenerator
{
  abstract protected void AddHeader();
  abstract protected void AddBody();
  abstract protected void AddFooter();

  // Template Method http://en.wikipedia.org/wiki/Template_method_pattern
  public FileInfo Generate(string sFileName)
  {
    FileInfo f = null;  
    //create file

    // either pass in the file to the below methods or use member vars + an additional write step 
    AddHeader();
    AddBody();
    AddFooter();

    // write out everything to the file
    return f;
  }
}

Next for each of the 3 unique combination, intermediate level classes like

接下来是3个独特组合中的每一个,中级等级

abstract public class UniqueHeaderFooterCombination1 : DocumentGenerator
{
  protected override void AddHeader()
  {
    Console.WriteLine("unique combination1 header");
  }
  protected override void AddFooter()
  {
    Console.WriteLine("unique combination1 footer");
  }
}

Finally the concrete classes for each unique filetype

最后是每个唯一文件类型的具体类

public class LetsSayCSVGenerator : UniqueHeaderFooterCombination1
{
  protected override void AddBody()
  {
    Console.WriteLine("csv body items");
  }
}

Couple this with a Factory to return the right type of Generator for a FileType and you're done.

将它与工厂相结合,为FileType返回正确类型的Generator,您就完成了。

abstract class DocumentGeneratorFactory
{
  public static DocumentGenerator GetGenerator(FileType eFileType)
  {
    switch (eFileType)
    {
      // a hash of FileType => Generator
      default:
        return new LetsSayCSVGenerator();
    }

  }
}

class Program
{
  static void Main(string[] args)
  {
    DocumentGenerator d = DocumentGeneratorFactory.GetGenerator(FileType.CSV);
    FileInfo f = d.Generate("ItsAlive.CSV");
  }
}

#2


As you say, constructors are not inherited.

如你所说,构造函数不是继承的。

Forcing the derived class to supply the details in the constructor would be the ideal case if you need to know the values during construction. If you don't, consider an abstract property that the derived class must provide:

如果您需要在构造期间知道值,则强制派生类在构造函数中提供详细信息将是理想的情况。如果不这样做,请考虑派生类必须提供的抽象属性:

// base-class
public abstract FileType FileType {get;}

// derived-class
public override FileType FileType {
    get {return FileType.Excel;} // or whatever
}

Note that unless you document it very clearly (and understand the implications) you shouldn't call a virtual method (such as the above) inside the constructor (since the derived type's constructor hasn't executed yet) - but it is fine after that.

请注意,除非您非常清楚地记录(并理解其含义),否则不应在构造函数中调用虚方法(如上所述)(因为派生类型的构造函数尚未执行) - 但在此之后就可以了。

Since the file-name isn't really dependent on the sub-type, I suspect I would leave that as a ctor parameter either way.

由于文件名实际上并不依赖于子类型,我怀疑我会将其作为ctor参数保留。

#3


You could make your base class that reads the headers & footers, and provides access to the attributes in the middle. Then define an interface that the dozens of specific attribute readers will implement. The interface could require accepting a "base class" and each implementation would define how the stuff in the middle is read.

您可以创建读取页眉和页脚的基类,并提供对中间属性的访问。然后定义几十个特定属性读取器将实现的接口。接口可能需要接受“基类”,每个实现都将定义如何读取中间的东西。

In practice, you'd have a common way to read the common parts and a common way to access the attributes. This parts are loosely coupled so changes would be less restrictive.

在实践中,您有一种通用的方法来阅读公共部分和访问属性的常用方法。这些部件松散耦合,因此变化的限制性较小。

#1


This looks like something a Template Method would solve... (Finally a place to use a pattern :)

这看起来像模板方法会解决的问题...(最后一个地方使用模式:)

public abstract class DocumentGenerator
{
  abstract protected void AddHeader();
  abstract protected void AddBody();
  abstract protected void AddFooter();

  // Template Method http://en.wikipedia.org/wiki/Template_method_pattern
  public FileInfo Generate(string sFileName)
  {
    FileInfo f = null;  
    //create file

    // either pass in the file to the below methods or use member vars + an additional write step 
    AddHeader();
    AddBody();
    AddFooter();

    // write out everything to the file
    return f;
  }
}

Next for each of the 3 unique combination, intermediate level classes like

接下来是3个独特组合中的每一个,中级等级

abstract public class UniqueHeaderFooterCombination1 : DocumentGenerator
{
  protected override void AddHeader()
  {
    Console.WriteLine("unique combination1 header");
  }
  protected override void AddFooter()
  {
    Console.WriteLine("unique combination1 footer");
  }
}

Finally the concrete classes for each unique filetype

最后是每个唯一文件类型的具体类

public class LetsSayCSVGenerator : UniqueHeaderFooterCombination1
{
  protected override void AddBody()
  {
    Console.WriteLine("csv body items");
  }
}

Couple this with a Factory to return the right type of Generator for a FileType and you're done.

将它与工厂相结合,为FileType返回正确类型的Generator,您就完成了。

abstract class DocumentGeneratorFactory
{
  public static DocumentGenerator GetGenerator(FileType eFileType)
  {
    switch (eFileType)
    {
      // a hash of FileType => Generator
      default:
        return new LetsSayCSVGenerator();
    }

  }
}

class Program
{
  static void Main(string[] args)
  {
    DocumentGenerator d = DocumentGeneratorFactory.GetGenerator(FileType.CSV);
    FileInfo f = d.Generate("ItsAlive.CSV");
  }
}

#2


As you say, constructors are not inherited.

如你所说,构造函数不是继承的。

Forcing the derived class to supply the details in the constructor would be the ideal case if you need to know the values during construction. If you don't, consider an abstract property that the derived class must provide:

如果您需要在构造期间知道值,则强制派生类在构造函数中提供详细信息将是理想的情况。如果不这样做,请考虑派生类必须提供的抽象属性:

// base-class
public abstract FileType FileType {get;}

// derived-class
public override FileType FileType {
    get {return FileType.Excel;} // or whatever
}

Note that unless you document it very clearly (and understand the implications) you shouldn't call a virtual method (such as the above) inside the constructor (since the derived type's constructor hasn't executed yet) - but it is fine after that.

请注意,除非您非常清楚地记录(并理解其含义),否则不应在构造函数中调用虚方法(如上所述)(因为派生类型的构造函数尚未执行) - 但在此之后就可以了。

Since the file-name isn't really dependent on the sub-type, I suspect I would leave that as a ctor parameter either way.

由于文件名实际上并不依赖于子类型,我怀疑我会将其作为ctor参数保留。

#3


You could make your base class that reads the headers & footers, and provides access to the attributes in the middle. Then define an interface that the dozens of specific attribute readers will implement. The interface could require accepting a "base class" and each implementation would define how the stuff in the middle is read.

您可以创建读取页眉和页脚的基类,并提供对中间属性的访问。然后定义几十个特定属性读取器将实现的接口。接口可能需要接受“基类”,每个实现都将定义如何读取中间的东西。

In practice, you'd have a common way to read the common parts and a common way to access the attributes. This parts are loosely coupled so changes would be less restrictive.

在实践中,您有一种通用的方法来阅读公共部分和访问属性的常用方法。这些部件松散耦合,因此变化的限制性较小。