我应该使我的对象属性为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;
}
}
根据您的域,您可以随时混合方法
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的Id
比Id = 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;
}
}
}
最后,如果你走这条路,代码生成器会很好地为你服务。