我应该使我的对象属性为null,还是对每个类型使用CLR默认值

本文关键字:类型 默认值 CLR 对象 我的 属性 null 我应该 | 更新日期: 2023-09-27 18:00:27

我一直在努力找出处理默认值的最佳方法。将ID值设置为0是有意义的,但如果它是一个货币值或其他最初没有设置的值,当您稍后在代码中遇到它时,就无法判断它是已设置还是已设置为0。如果一个货币值被设置为null,那么你就知道它还没有被设置。此外,在处理数据库时,很容易知道是否需要向字段写入null值,而不是试图弄清楚它是否应该为null。

处理这个问题的公认方法是什么?

Class MyModel
{
    public int Id {get;set;}
    public string Title {get;set;}
    public DateTime CreatedDate {get;set;}
    public bool IsActive {get;set;}
    //CLR will automatically set these values
    Public MyModel()
    {
        Id = 0; 
        Title = String.Empty;
        CreatedDate = "1/1/0001";
        IsActive = false;
    }
}

Class MyModel
{
    public int? Id {get;set;}
    public string Title {get;set;}
    public DateTime? CreatedDate {get;set;}
    public bool? IsActive {get;set;}
    //CLR will automatically set these values
    Public MyModel()
    {
        Id = null; 
        Title = null;
        CreatedDate = null;
        IsActive = null;
    }
}

我应该使我的对象属性为null,还是对每个类型使用CLR默认值

根据您的域,您可以随时混合方法

static class ID
{
    public const int Unassigned = -1;
}
class MyModel
{
    public int Id { get; private set; }
    public string Title { get; set; }
    public DateTime CreatedDate { get; set; }
    public bool IsActive { get; set; }
    public bool? IsAwesome { get; set; }
    Model () 
    {
        // you may use "default" constants...
        Id = ID.Unassigned;
    }
    // you may use optional parameters or overloads
    public MyModel (string title,
        DateTime created = DateTime.Now, // default values may be concrete 
        bool? isAwesome = null)          // or nullable as well
        : this ()                        // and you can chain-call constructors!
    {
        Title = title ?? "<no title>";   // you don't always want null to come through
        CreatedDate = created;     
        IsAwesome = isAwesome;    
    }
}
// Possible usages:
var model = new MyModel ("Hello", new DateTime (2001, 1, 1));
var model = new MyModel ("world", isAwesome: true);
var model = new MyModel (null) {
    IsActive = true
};

某些属性具有null值可能是有意义的,如"未设置"。

在您的示例中,一个模型在持久化到数据库之前可能真的不具有Id。如果是这种情况,并且无id模型在业务逻辑方面是有意义的,则可为null的IdId = 0更好。然而,如果您的应用程序从不使用无id模型,并且通常期望Id等于某个值,那么编写将是疯狂的

if (model.Id != null)

每次你想用它做点什么。

在这种情况下,您可能应该默认使用Id = 0
您也可以引入一个常量(正如我在上面所做的那样),尽管我不建议将其用于除id之外的任何东西,并且只有在其他地方的代码大量使用它们的情况下。

同样,一切都取决于域
您的工作是确保违反业务规则的对象不会轻易创建

处理这个问题的公认方法是什么?

是否接受?这取决于域。

如果一个货币值被设置为null,那么你就知道它还没有被设置。

不一定。想象一下,我正在使用一个银行应用程序,我想搜索一个特定的交易,然后我得到一个对话框,看起来像这样:

Enter the fields you know:
Transaction date: 6/26/2011
Payee: Apple
Amount:

现在TransactionSearchParameters.Amount应该设置为null。你无法将其与未设置区分开来。

此外,在处理数据库时,很容易知道是否需要向字段写入null值,而不是试图弄清楚它是否应该为null。

你应该花更多的时间正确地建模你的域,然后让ORM弄清楚如何正确地将这些东西放入数据库。

在这里添加一个想法,在适当的时候,复杂类型总是有null对象模式。

这取决于您将如何使用代码。如果属性是像integer&字符串,默认值更好,如果属性本身就是对象,我使用了null,因为在C#/Java/PHP中,对象引用实际上是对象指针,使用起来更好。

但是,如果您的属性是集合,如列表或映射,则"更好的做法"是创建集合,并将其保留为空,而不是null。

干杯。

嗯。。。"最好"的答案(在那里很有主见,但我有资格)是当你不需要区分两者时,因为只有一种可能的状态,那就是有效:

class MyModel
{
    public int Id {get; private set;}
    public string Title {get; private set;}
    public DateTime CreatedDate {get; private set;}
    public bool IsActive {get; private set;}
    Public MyModel(int Id, string Title, DateTime CreatedDate, bool IsActive)
    {
        this.Id = Id; 
        this.Title = Title;
        this.CreatedDate = CreatedDate;
        this.IsActive = IsActive;
    }
}

我知道这并不总是可能的,例如Query by Example。

通常避免使用像"将ID值设置为0很有意义…"这样的"幻数"。一旦你做到了这一点,现在你编写的每一段代码都必须进行编码,以了解这些幻数是什么以及它们的含义。这是很少实现的,并且充满了令人讨厌和容易出错的代码。

如果您只是必须区分一个有值的字段和没有值的字段,那么后面的示例会更好一些。至少在这里,值类型显式有效或无效。但是,使用Nullable<T> 意味着您必须使用不同的方法来确定类、字符串或其他引用类型是否无效。

IMO,你最好有以下内容,尽管你会看到它变得非常冗长。

class MyModel
{
    private int _id;
    public bool HasId { get; set; }
    public int Id
    {
        get
        {
            if (!HasId) throw new System.InvalidOperationException();
            return _id;
        }
        set
        {
            HasId = true;
            _id = value;
        }
    }
    private string _title;
    public bool HasTitle { get; set; }
    public string Title
    {
        get
        {
            if (!HasTitle) throw new System.InvalidOperationException();
            return _title;
        }
        set
        {
            if (value == null) throw new System.ArgumentNullException("Title");
            HasTitle = true;
            _title = value;
        }
    }
    private DateTime _createdDate;
    public bool HasCreatedDate { get; set; }
    public DateTime CreatedDate
    {
        get
        {
            if (!HasCreatedDate) throw new System.InvalidOperationException();
            return _createdDate;
        }
        set
        {
            HasCreatedDate = true;
            _createdDate = value;
        }
    }
    private bool _isActive;
    public bool HasIsActive { get; set; }
    public bool IsActive
    {
        get
        {
            if (!HasIsActive) throw new System.InvalidOperationException();
            return _isActive;
        }
        set
        {
            HasIsActive = true;
            _isActive = value;
        }
    }
}

最后,如果你走这条路,代码生成器会很好地为你服务。