【问题标题】:C# class with required fields具有必填字段的 C# 类
【发布时间】:2013-09-04 19:56:23
【问题描述】:

我有类,创建对象时必须在其中的所有字段。我的解决方案:

class MyClass
{
    private string Field1;
    private int Field2;

    public MyClass(string Field1, int Field2)
    {
        this.Field1 = Field1;
        this.Field2 = Field2;
    }
}

但是字段可能大于2,代码看起来很脏。有没有更优雅的方法?

【问题讨论】:

  • 为什么脏?它有什么问题?
  • 为避免命名冲突,我建议在字段前使用“_”(下划线)。

标签: c# constructor field params


【解决方案1】:

将所需的字段传递给构造函数应该没问题。您的代码看起来还不算脏,但如果它开始增长 10 个必填字段,那么最好创建一个包含所有必填字段的对象,然后在创建对象(构造函数)时使用该对象。

现在这还不算脏

class MyClass
{
    private string Field1;
    private int Field2;

    public MyClass(string Field1, int Field2)
    {
        this.Field1 = Field1;
        this.Field2 = Field2;
    }
}

如果变成这样

class MyClass
{
    private string Field1;
    private int Field2;

    public MyClass(string Field1, int Field2, int Field3, int Field4, int Field5, int Field6, int Field7, int Field8, int Field9, int Field10)
    {
        this.Field1 = Field1;
        this.Field2 = Field2;
        //Set them
    }
}

那最好有这个

    class RequiredFields
{
    //All required fields
}

class MyClass
{
    private string Field1;
    private int Field2;

    public MyClass(RequiredFields requiredFields)
    {
        this.Field1 = requiredFields.Field1;
        this.Field2 = requiredFields.Field2;
        //Set them
    }
}

【讨论】:

  • 是的,这是一个更好的解决方案:几个字段可以组合成一个结构
  • 大成本 - 为替换参数创建结构
  • 这取决于他的场景,如果字段是不可变的,确定结构。结构消耗的堆内存较少,但复制时间比引用副本长。而这里也只有他能确定什么更可行。也许是类,也许是结构。根据经验:如果对象 (1) 很小,(2) 在逻辑上是不可变的值,并且 (3) 有很多,那么我会考虑将其设为结构。否则我会坚持使用引用类型。
  • 那么创建引用类型(类)的成本高吗?它只消耗更少的堆内存与类。 :)
  • 在新结构的情况下,您无法理解哪些字段是默认的,哪些不是默认的。
【解决方案2】:

可以使用 System.ComponentModel.DataAnnotations.RequiredAttribute

[Required]
public string Field1{ get; set; }

【讨论】:

    【解决方案3】:

    您可以使用带有设置器而不是字段的属性,然后使用 IsValid() 方法检查对象在使用之前是否已完全“填充”。但是,如果您要在代码中同时设置所有值,那看起来不会更整洁。

    由于构造函数参数列表较长,Named Arguments 可以使调用更具可读性。

    【讨论】:

    • 如果代码的用户(甚至是你,几个月/几年后)忘记打电话给IsValid()怎么办?这是一个糟糕的解决方案。如果您 100% 希望字段存在,则不得通过构造函数、具有执行此类验证的 Build() 方法的构建器模式等为用户提供初始化它们的任何其他选项。
    • @async 如果您的对象属于“告诉不问”类型,并且行为通过公共方法公开,则可以在每个公共方法的顶部调用 IsValid()对象本身。如果您将对象仅用作属性包,则可以在 getter 中调用 IsValid() 以确保对象在读取之前已完全写入。后者在需要在两个不同位置填充对象的情况下可能很有用。这两种情况听起来都不是非常优美的代码,但无论哪种情况,用户都不需要记住任何内容。
    【解决方案4】:

    确实没有其他方法可以确保用户为每个字段提供一个值,但您可以自己提供一个默认值。

    例如,您可以提供一个替代构造函数,它构造一个具有某些默认字段值的对象,如下所示:

    public MyClass() : this(string.Empty, -1)
    {
    }
    
    public MyClass(string Field1, int Field2)
    {
        this.Field1 = Field1;
        this.Field2 = Field2;
    }
    

    或者:

    public MyClass(string Field1 = "", int Field2 = -1)
    {
        this.Field1 = Field1;
        this.Field2 = Field2;
    }
    

    【讨论】:

      【解决方案5】:

      您可以拥有这样的东西,然后在您尝试访问其中的字段时引用该对象。

      class MyClass
      {
          private MyObject Test;
      
          public MyClass(MyObject Test)
          {
              this.Test = Test;
          }
      
      
      }
      class MyObject
      {
          private string Field1;
          private int Field2;
      
          // Constructor / methods to set up fields
      }
      

      【讨论】:

        【解决方案6】:

        我认为你需要私有构造函数、工厂方法和命名参数,例如:

        class MyClass
        {
            private string Field1;
            private int Field2;
        
            private MyClass()
            {
        
            }
            public MyClass GetMyClassInstance(string Field1=string.Empty, int Field2=-1)
            {
                this.Field1 = Field1;
                this.Field2 = Field2;
            }
        }
        

        现在您可以添加任意数量的参数来创建 MyClass 对象。

        【讨论】:

        • 这是代码异味。如果他碰巧有 2 个以上的必填字段具有不必要的默认值,并且要求更改,尤其是默认值,那么更新代码和在这里定义可选参数很繁琐,这不是解决方案。它只是在将来阅读代码时增加了更多复杂性。
        • 哦,添加私有构造函数也没用。如果要使用工厂方法/命名参数创建对象,不妨创建一个工厂类来实例化 MyClass 对象。 :)
        • 在这种情况下不需要创建工厂类。工厂方法 - 全部解决。如果您需要创建没有默认字段的对象 - its other logic and then you need change signature this method or add new method. At case with new structure you cant 了解哪些字段是默认字段,哪些不是默认字段。我认为为这种情况创建新课程并不好。
        猜你喜欢
        • 1970-01-01
        • 2020-08-31
        • 1970-01-01
        • 1970-01-01
        • 2020-08-28
        • 2014-11-23
        • 2014-08-07
        • 2014-08-06
        • 2023-03-30
        相关资源
        最近更新 更多