【问题标题】:Check if object is defined after initialization in c#在c#中初始化后检查对象是否定义
【发布时间】:2017-01-24 00:19:58
【问题描述】:

我有以下对象(类)。

namespace Temp.Models
{
    public class CurrentClass
    {
        private double _firstCoefficient;
        private double _secondCoefficient;

        public double FirstCoefficient
        {
            get { return _firstCoefficient; }
            set { _firstCoefficient= value; }
        }
        public double SecondCoefficient
        {
            get { return _secondCoefficient; }
            set { _secondCoefficient= value; }
        }
    }
}

下面的类利用了上面的对象,因此初始化对象如下:

namespace Temp.Models
{
    public class MainClass
    {
        private CurrentClass _currentClass = new CurrentClass();

        public CurrentClass CurrentClass
        {
            get { return _currentClass; }
            set { _currentClass = value; }
        }
    }
}

如果满足某些条件,我会按如下方式定义变量:

MainClass currentObject = new MainClass();
//if conditions are met
currentObject.CurrentClass.FirstCoefficient = 0;
currentObject.CurrentClass.SecondCoefficient = 5;

但是如果条件从未满足并且我从未定义上述变量怎么办。检查对象是否从未定义过的最佳方法和/或最佳方法是什么?

我可以做以下检查:

if(currentObject.CurrentClass.FirstCoefficient != 0 && currentObject.CurrentClass.SecondCoefficent != 0)

但是这些值可以定义为 0...所以我不知道该怎么做。

非常感谢任何帮助!

【问题讨论】:

  • 考虑使用类型“double?”而不是“双”,那么你可以检查 null
  • 我认为您不只是对条件进行相同的检查而不是检查CurrentClass 实例是有原因的?
  • @ScottPerham 我明白你的意思,这将是这个对象的合理解决方案,但我实际上还有其他具有多种不同类型的对象。包括枚举等等……那么在这种情况下你会怎么做?
  • 最好的办法是使用不可变类完全避免这个问题(通过构造函数进行参数化,使所有字段/属性只读)。因此,任何现有对象都必须处于有效状态。如果您不能这样做,请使用Nullable<T>,但要准备好到处进行大量不必要的一致性检查。
  • @Crowcoder 我将如何检查实例本身?我尝试设置 CurrentClass != null 但它认为该对象即使未定义(仅在初始化时)也确实不为 null...

标签: c# .net object if-statement syntax


【解决方案1】:

这些是可用于通过描述、示例和简要评估/意见来解决问题的一些原则。

1。通过构造函数进行参数化

根据 OOP 原则,构造函数是用于将对象初始化为有效状态的方法。不变性的概念更进一步,不允许任何更改,完全避免无效状态。

在对象的 API 不允许无效状态的情况下,也存在妥协的可能性。

有了这个概念,你会到达:

namespace Temp.Models
{
    public class CurrentClass
    {
        public double FirstCoefficient { get; private set; }
        public double SecondCoefficient { get; private set; }

        public CurrentClass(double firstCoefficient, double secondCoefficient)
        {
            FirstCoefficient = firstCoefficient;
            SecondCoefficient = secondCoefficient;
        }

        // if mutability is required - this is needless as the constructor is
        // the same but if there was more complex state, methods like this would make
        // sense, mutating only parts of the state
        public void SetCoefficients(double firstCoefficient, double secondCoefficient)
        {
            FirstCoefficient = firstCoefficient;
            SecondCoefficient = secondCoefficient;
        }
    }
}

总结:

  • CurrentClass 的每个实例化始终处于有效状态,避免了很多一致性检查(改进了封装)

  • 需要更多的代码来编写(但是由于前面的一点,你节省了很多其他代码)

  • 你需要事先知道系数。

2。使用可为空的类型

可空类型将“附加”值添加到类型,即“未定义”状态。引用类型 (class) 在设计上可以为空,而值类型 (struct) 需要标记为可为空,可以使用Nullable<T> 或简写为T?

这允许对象处于无效状态并对其进行具体说明。这从不变性进入一致性尺度的另一端,因为具有多个可为空字段的对象具有许多无效状态。

示例代码:

namespace Temp.Models
{
    public class CurrentClass
    {
        public double? FirstCoefficient { get; set; }
        public double? SecondCoefficient { get; set; }
    }
}

现在这可以很好地实例化并且可以随时更改:

public CurrentClass CreateCurrentClass()
{
    var currentClass = new CurrentClass { FirstCoefficient = 1.0 };
    var secondCoefficient = RetrieveSecondCoefficient();
    currentClass.SecondCoefficient = secondCoefficient;

    return currentClass;
}

但是,您需要在使用对象的任何地方进行有效性检查。

public bool IsValid(CurrentClass currentClass)
{
    // what if FirstCoefficient has value and SecondCoefficient doesn't,
    // is that always an invalid state?
    return currentClass.FirstCoefficient.HasValue
        && currentClass.SecondCoefficient.HasValue;
}

总结:

  • 只需很少的代码即可启动并运行 DTO

  • 使用此类模型需要进行大量一致性检查(以及相关的脑痛)

  • 缺少封装 - 任何采用CurrentClass 的方法都可能改变其有效性,从而使前面的观点变得更糟。这可以通过在需要只读访问权限的地方使用只读接口来缓解。

总结

还有许多其他方法通常介于上述两种方法之间。例如,您可以为每个对象使用一个有效性标志(SergeyS 的响应)并简化外部有效性检查,但在类中有更多代码并且需要更深入的思考。

就个人而言,我更喜欢不变性。编写更多的猴子代码,但由于干净的设计,肯定会在未来得到回报。

如果没有广泛的知识,就很难推理一个没有不变性的复杂系统。这在团队中工作时尤其痛苦——通常每个人只知道代码库的一部分。

可悲的是,并非总是可以让所有东西都保持不变(例如视图模型):然后我倾向于尽快将对象转换为内部不可变模型。

【讨论】:

  • 感谢您的深入分析!这是很大的帮助!
【解决方案2】:

鉴于您已经写过,我会将Initialize() 方法和Initialized 属性添加到您的MainClass 类中。类似的东西:

public class MainClass
{
    private CurrentClass _currentClass = new CurrentClass();

    public CurrentClass CurrentClass
    {
        get { return _currentClass; }
        set { _currentClass = value; }
    }

    public bool Initialized {get; private set;}

    public void Initialize()
    {
        this.CurrentClass.FirstCoefficient = 0;
        this.CurrentClass.SecondCoefficient = 5;

        this.Initialized = true;
    }
}

在满足您的条件时调用Initialize() 方法。 稍后在代码中您可以检查if(currentObject.Initialized)。注意 `Initialized' 属性的私有设置器,它将确保该标志不会被外部代码意外设置。

根据你的需要,你可以更进一步,将初始化的参数直接作为参数传递给Initialize()方法。

【讨论】:

  • 谢谢,我相信这会奏效,有很多解决方案。因此,在选择正确答案之前,我将对其进行探索,看看哪种方法是最好的。感谢您的意见!
【解决方案3】:

您有几种方法,例如在构造函数中强制值正确,或者让另一个变量告诉对象是否还没有值,例如 System.Drawing.Point 具有静态“空”属性。但是在您的简单对象的这种情况下,您的主类显式创建 CurrentClass 的实例,因此此时该对象应该是正确的并且应该设置系数。如果您依赖其他代码设置这些值以稍后执行其他操作,则超出这两个对象的范围。

更新:perharps 分享真正问题所在的细节会更好,因为我有一种感觉,试图提供一个简化的示例最终隐藏了真正的问题。

【讨论】:

  • 真正的问题是我正在从一个正在发送的文件中读取所有这些信息。如果这个文件有数据,那么我根据需要输入信息(定义已经初始化的变量)。跨度>
  • 在这种情况下,我只会在数据成功进入时创建一个对象(主类),而不是 null,或者如果数据不可用则生成异常。
猜你喜欢
  • 1970-01-01
  • 2019-01-25
  • 2010-12-06
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多