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

时间:2011-06-27 17:27:34

标签: c# asp.net architecture

我一直在努力找出处理默认值的最佳方法。将ID值设置为0是有意义的,但如果它是金钱值或其他未初始设置的值,当您在代码中稍后遇到它时,无法判断它是否已设置或设置为0。将money值设置为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;
    }
}

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 个答案:

答案 0 :(得分:3)

  

处理此问题的可接受方法是什么?

接受?这取决于域名。

  

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

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

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

现在TransactionSearchParameters.Amount应该设置为null。你无法区分它没有被设置。

  

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

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

答案 1 :(得分:3)

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

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模型在业务逻辑方面有意义,则可以为空的Id优于Id = 0。但是,如果你的应用程序永远不能使用无标识模型,并且通常希望Id等于某些东西,那么编写它会很疯狂

if (model.Id != null)

每次你想用它做点什么。

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

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

答案 2 :(得分:2)

只需添加一个想法,适合使用的复杂类型总是有null object pattern

答案 3 :(得分:0)

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

但是,如果你的属性是集合,比如列表或地图,它是一个“更好的做法”,创建集合,并将其留空,而不是null。

干杯。

答案 4 :(得分:0)

嗯......'最好'的答案(非常痴迷于此,但我有资格)是你不需要区分两者,因为只有一种可能的状态,即有效状态:

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&lt; T&gt;。表示您必须使用不同的方法来确定类,字符串或其他引用类型是否无效。

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

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

相关问题