部分类,以避免实例化为同一文件创建字符串的多个类

时间:2017-02-28 13:02:40

标签: c#

项目类型:从ASP.NET应用程序调用C#类库 框架版本:4.5.1

我一直在寻找关于部分课程的所有内容,我发现的所有参考资料都是代码气味,但我发现所有这些都是关于上帝课程,而不是。我需要帮助来决定这种情况的最佳方法。

我知道部分类通常用于设计器生成的代码,但是......我无法在下面列出的选项之间做出决定。我的选择2和部分课程是一个非常糟糕的主意吗?

我正在编写一个程序来创建非典型的CSV文件,这意味着该文件不包含列数据。每行包含不同的数据和不同数量的列。

每个方法使用哪个选项都需要访问两个数据集和一个包含Document的{​​{1}}类,每个方法都会添加一行(字符串)。

我所知道的:

  • 每一行都有一个非唯一的类型标识符,例如" H00"," H10"," D50"," D55&# 34; ...

  • 每行根据行类型标识符具有固定数量的列 有些行与其他行相关,而有些行则不然。

  • 大约有25个(给出或取5个)类型的行,因此大约有25个文件部分属于一个构造函数。这个数字可以增长,但最多不超过40个。

我不想要的东西:

  • 一个大类,每个行类型都有一个方法。

  • 使用一堆辅助方法的一个重要方法。

选项1:为每种线型创建一个单独的类。

选项1问题:这会创建大量的类实例。

选项2:创建名为" Line"的部分类。每个行类型都有一个单独的* .cs文件,其中包含与正在创建的行类型匹配的方法。在这个例子中,我想我会使用类级属性来处理在构造函数中初始化的数据集和文档。

选项2:部分类被认为是代码味道,因为它们难以管理并使代码更复杂。

典型方法,省略参数以保持此示例简单:

public List<string>

编辑选择答案后: @Hristo,每个文件都需要执行每一行,有些方法需要不同的参数。每条生产线的要求都会发生变化。

是否需要某一行的决定取决于其中一个数据集中的数据。例如,当我创建发票时,如果发票没有折扣,那么我就不会为折扣创建一条线,或者如果订单有运费,则会确定是否会写入运费的行。我认为如果在创建线的方法中确定了这个逻辑,那么编写和维护是最容易的。如果不需要该行,那么将返回零长度,然后该行不会被添加到Doc.Lines

1 个答案:

答案 0 :(得分:3)

你应该问问自己从长远来看哪些是最易管理的。什么是最容易阅读和维护的。

解决方案1:

我走这条路:

public class Document
{
    //The document class would not be part of the partial class
    //The document has other properties, I left them out to keep it simple
    public List<string> Lines { get; set; }

    public Document()
    {
        this.Lines = new List<string>
    }
}

public interface ILine
{
    string[] ProduceLine(DataSet ds1, DataSet ds2);
}

public class H01 : ILine
{
    public string[] ProduceLine(DataSet ds1, DataSet ds2)
    {
        string[] fields = new string[3];
        fields[0] = "855";
        fields[1] = "value from datatable";
        fields[2] = "value from datatable";

        return fields;
    }
}

public class H10 : ILine
{
    public string ProduceLine(DataSet ds1, DataSet ds2)
    {
        string[] fields = new string[27];
        fields[0] = "855";
        fields[10] = "other from datatable";
        fields[16] = "other data";

        return fields;
    }
}

var doc = new Document();

foreach (ILine line in lines)
{
    doc.Lines.Add(string.Join(",", line.ProduceLine(ds1, ds2)));
}

修改(lines来自哪里):

嗯,真的取决于你。最简单的例子:

var lines = new List<ILine>(new []
{
    new H10(),
    new H01()
});

如果您不必了解每个实现并且只需要在构造函数中注入所有这些实现,那就更好了。但这实际上取决于您的商业案例。您如何确定要使用哪些实现?在所有情况下,你需要所有人吗?等

e.g:

public class MyWorker
{
  // This would require that you setup Inversion of Control container and use it to resolve MyWorker.
  // See: http://stackoverflow.com/questions/1961549/resolving-ienumerablet-with-unity
  public MyWorker(IEnumerable<ILine> lines)
  {
     this.lines = lines;
  }
}

解决方案2:

或者,如果你真的喜欢你的部分构造,你可以使用这样的委托:

delegate string[] ProduceLine(DataSet ds1, DataSet ds2);

partial class LineMethods // file named: H01.cs
{
    public string[] H01(DataSet ds1, DataSet ds2)
    {
        string[] fields = new string[3];
        fields[0] = "855";
        fields[1] = "value from datatable";
        fields[2] = "value from datatable";

        return fields;
    }
}

partial class LineMethods // File named: H10
{
    public string[] H10(DataSet ds1, DataSet ds2)
    {
        string[] fields = new string[27];
        fields[0] = "855";
        fields[10] = "other from datatable";
        fields[16] = "other data";

        return fields;
    }
}

var h01Method = new ProduceLine(LineMethods.H01);
doc.Lines.Add(string.Join(",", h01Method.Invoke(ds1, ds2));

您决定什么更容易阅读和维护。