我应该使我的对象属性可以为空还是为每种类型使用CLR默认值?

时间:2022-10-10 07:07:49

I have been trying to figure out the best way to handle default values. Setting a ID value to 0 makes sense, but if it is a money value or other that is not initially set, when you encounter it later in your code, it is impossible to tell if it has been set or was set to 0. If a money value is set to null, then you know it has not been set. Additionally, when dealing with the database, it is simple to know if you need to write a null value to a field vs trying to figure out if it is supposed to be null or not.

我一直试图找出处理默认值的最佳方法。将ID值设置为0是有意义的,但如果它是货币值或其他未初始设置的值,当您在代码中稍后遇到它时,无法判断它是否已设置或设置为0。 money值设置为null,然后您知道它尚未设置。此外,在处理数据库时,很容易知道是否需要将空值写入字段而不是试图确定它是否应该为空。

What is the accepted way to handle this?

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

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;
    }
}

vs

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;
    }
}

5 个解决方案

#1


3  

You can always mix approaches, depending on your domain.

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

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
};

It may make sense for some attributes to have null values, as in “not set”.

某些属性具有空值可能是有意义的,如“未设置”。

In your example, perhaps a model really doesn't have an Id before it is persisted to the database. If this is the case, and an id-less model makes sense in terms of business logic, a nullable Id is better than Id = 0. However, if your application never works with id-less models, and usually expects Id to equal something, it would be crazy to write

在您的示例中,可能模型在持久保存到数据库之前确实没有Id。如果是这种情况,并且无ID模型在业务逻辑方面有意义,则可以为空的Id优于Id = 0.但是,如果您的应用程序从不使用无ID模型,并且通常期望Id等于某些内容写起来会很疯狂

if (model.Id != null)

each time you want to do something with it.

每次你想用它做什么。

In this case, you should probably go with Id = 0 by default.
You could also introduce a constant (as I've done above) though I wouldn't recommend it for anything but ids, and only in case they are heavily used by code elsewhere.

在这种情况下,您可能应该默认使用Id = 0。你也可以引入一个常量(正如我上面所做的那样)虽然我不推荐它用于除了id以外的任何东西,并且只有在其他地方的代码中大量使用它们时才会这样。

Again, everything depends on the domain.
Your job is to ensure that objects violating business rules can't be created easily.

同样,一切都取决于域名。您的工作是确保无法轻松创建违反业务规则的对象。

#2


3  

What is the accepted way to handle this?

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

Accepted? It depends on the domain.

公认?这取决于域名。

If a money value is set to null, then you know it has not been set.

如果money值设置为null,那么您知道它尚未设置。

Not necessarily. Imagine I'm using a banking application, and I want to search for a particular transaction, and I get a dialog that looks like this:

不必要。想象一下,我正在使用银行应用程序,我想搜索特定的事务,然后我得到一个如下所示的对话框:

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

Now TransactionSearchParameters.Amount should be set to null. You can't distinguish this from it not being set.

现在TransactionSearchParameters.Amount应该设置为null。您无法区分它与未设置。

Additionally, when dealing with the database, it is simple to know if you need to write a null value to a field vs trying to figure out if it is supposed to be null or not.

此外,在处理数据库时,很容易知道是否需要将空值写入字段而不是试图确定它是否应该为空。

You should spend more time modeling your domain properly, and then let an ORM figure out how to get that stuff into the database properly.

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

#3


2  

Just an idea to add here, there is always the null object pattern for complex types when appropriate to use.

只是在这里添加一个想法,在适当使用时,总是存在复杂类型的空对象模式。

#4


0  

It depends how are you going to use your code. If the properties are simple types like integers & strings, default values are better, if the properties are objects by themselves, I used nulls, because in C# / Java / PHP, objects references are really object pointers and better to use.

这取决于您将如何使用您的代码。如果属性是整数和字符串这样的简单类型,默认值更好,如果属性本身是对象,我使用空值,因为在C#/ Java / PHP中,对象引用实际上是对象指针,更好用。

But, if your properties are collections, like lists or maps , its a "better practice" , to create the collection, and leave it empty, instead of null.

但是,如果您的属性是集合,如列表或映射,它是一个“更好的实践”,创建集合,并将其保留为空,而不是null。

Cheers.

#5


0  

Well... the 'best' answer (very opinionated there, but I'm entitled) is when you don't need to differentiate between the two because there is only one possible state, that of being valid:

那么......“最好的”答案(在那里非常自以为是,但我有资格)就是当你不需要区分两者时,因为只有一种可能的状态,即有效状态:

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;
    }
}

I know this isn't always possible, for instance Query by Example.

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

Using 'magic numbers' like your "Setting a ID value to 0 makes sense..." is generally avoided. Once you do this now every piece of code you write must coded to know what these magic number are and what they mean. This is seldom achieved and full of nasty looking and error prone code.

通常可以避免使用像“将ID值设置为0有意义......”这样的“幻数”。一旦你这样做了,你编写的每一段代码都必须编码才能知道这些神奇数字是什么以及它们的含义。这很少实现,并且充满讨厌的外观和容易出错的代码。

If you simply MUST have the distinction between a field having a value and not, your later example is a little better. At least here you're value types are explicitly valid or invalid. However, using Nullable<T> means that you must use a different means to determine if a class, string, or other reference type is invalid.

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

IMO, You are better off with the following, although it becomes very verbose as you will see.

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;
        }
    }
}

Lastly, If you are going this route a code generator will serve you well.

最后,如果您要使用此路由,代码生成器将为您提供良好的服务。

#1


3  

You can always mix approaches, depending on your domain.

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

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
};

It may make sense for some attributes to have null values, as in “not set”.

某些属性具有空值可能是有意义的,如“未设置”。

In your example, perhaps a model really doesn't have an Id before it is persisted to the database. If this is the case, and an id-less model makes sense in terms of business logic, a nullable Id is better than Id = 0. However, if your application never works with id-less models, and usually expects Id to equal something, it would be crazy to write

在您的示例中,可能模型在持久保存到数据库之前确实没有Id。如果是这种情况,并且无ID模型在业务逻辑方面有意义,则可以为空的Id优于Id = 0.但是,如果您的应用程序从不使用无ID模型,并且通常期望Id等于某些内容写起来会很疯狂

if (model.Id != null)

each time you want to do something with it.

每次你想用它做什么。

In this case, you should probably go with Id = 0 by default.
You could also introduce a constant (as I've done above) though I wouldn't recommend it for anything but ids, and only in case they are heavily used by code elsewhere.

在这种情况下,您可能应该默认使用Id = 0。你也可以引入一个常量(正如我上面所做的那样)虽然我不推荐它用于除了id以外的任何东西,并且只有在其他地方的代码中大量使用它们时才会这样。

Again, everything depends on the domain.
Your job is to ensure that objects violating business rules can't be created easily.

同样,一切都取决于域名。您的工作是确保无法轻松创建违反业务规则的对象。

#2


3  

What is the accepted way to handle this?

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

Accepted? It depends on the domain.

公认?这取决于域名。

If a money value is set to null, then you know it has not been set.

如果money值设置为null,那么您知道它尚未设置。

Not necessarily. Imagine I'm using a banking application, and I want to search for a particular transaction, and I get a dialog that looks like this:

不必要。想象一下,我正在使用银行应用程序,我想搜索特定的事务,然后我得到一个如下所示的对话框:

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

Now TransactionSearchParameters.Amount should be set to null. You can't distinguish this from it not being set.

现在TransactionSearchParameters.Amount应该设置为null。您无法区分它与未设置。

Additionally, when dealing with the database, it is simple to know if you need to write a null value to a field vs trying to figure out if it is supposed to be null or not.

此外,在处理数据库时,很容易知道是否需要将空值写入字段而不是试图确定它是否应该为空。

You should spend more time modeling your domain properly, and then let an ORM figure out how to get that stuff into the database properly.

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

#3


2  

Just an idea to add here, there is always the null object pattern for complex types when appropriate to use.

只是在这里添加一个想法,在适当使用时,总是存在复杂类型的空对象模式。

#4


0  

It depends how are you going to use your code. If the properties are simple types like integers & strings, default values are better, if the properties are objects by themselves, I used nulls, because in C# / Java / PHP, objects references are really object pointers and better to use.

这取决于您将如何使用您的代码。如果属性是整数和字符串这样的简单类型,默认值更好,如果属性本身是对象,我使用空值,因为在C#/ Java / PHP中,对象引用实际上是对象指针,更好用。

But, if your properties are collections, like lists or maps , its a "better practice" , to create the collection, and leave it empty, instead of null.

但是,如果您的属性是集合,如列表或映射,它是一个“更好的实践”,创建集合,并将其保留为空,而不是null。

Cheers.

#5


0  

Well... the 'best' answer (very opinionated there, but I'm entitled) is when you don't need to differentiate between the two because there is only one possible state, that of being valid:

那么......“最好的”答案(在那里非常自以为是,但我有资格)就是当你不需要区分两者时,因为只有一种可能的状态,即有效状态:

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;
    }
}

I know this isn't always possible, for instance Query by Example.

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

Using 'magic numbers' like your "Setting a ID value to 0 makes sense..." is generally avoided. Once you do this now every piece of code you write must coded to know what these magic number are and what they mean. This is seldom achieved and full of nasty looking and error prone code.

通常可以避免使用像“将ID值设置为0有意义......”这样的“幻数”。一旦你这样做了,你编写的每一段代码都必须编码才能知道这些神奇数字是什么以及它们的含义。这很少实现,并且充满讨厌的外观和容易出错的代码。

If you simply MUST have the distinction between a field having a value and not, your later example is a little better. At least here you're value types are explicitly valid or invalid. However, using Nullable<T> means that you must use a different means to determine if a class, string, or other reference type is invalid.

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

IMO, You are better off with the following, although it becomes very verbose as you will see.

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;
        }
    }
}

Lastly, If you are going this route a code generator will serve you well.

最后,如果您要使用此路由,代码生成器将为您提供良好的服务。