属性 从不为 null c#
Property never null c#
在重构代码时,我想到了如下实例
private string _property = string.Empty;
public string Property
{
set { _property = value ?? string.Empty); }
}
稍后在方法中我看到以下内容:
if (_property != null)
{
//...
}
假设_property
仅由Property
的setter设置,这段代码是不是多余?
也就是说,有什么办法可以通过反射魔法或其他方法使 _property
永远为空吗?
Assuming that _property is only set by the setter of Property, is this
code redundant?
没错,就是多余的。这就是 Properties 的实际用途。我们不应该直接访问 class 的字段。我们应该使用 属性 访问它们。所以在相应的 setter 中,我们可以嵌入任何逻辑,我们可以放心,每次我们尝试设置一个值时,一旦 more.This 参数成立,即使对于 class。在方法中,我们必须使用属性而不是实际字段。此外,当我们要读取一个字段的值时,我们应该使用相应的getter。
一般来说,属性增强了封装的概念,这是面向对象编程 OOP 的支柱之一。
很多时候,当我们想要设置一个值时,没有任何逻辑可以应用。以下面的例子为例:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
我们已声明 class 代表客户。 Customer 对象应具有三个属性 Id
、FirstName
和 LastName
.
一个直接的问题,当有人读到这篇文章时 class 为什么有人要在这里使用属性?
答案还是一样的,他们提供了封装的机制。但是,让我们考虑一下这对长期 运行 有何帮助。假设有一天有人决定客户的名字应该是长度小于 20 的字符串。如果上面的 class 声明如下:
public class Customer
{
public int Id;
public string FirstName;
public string LastName;
}
那么我们应该在我们创建的每个实例中检查 FirstName
的长度!否则,如果我们选择了带有属性的声明,我们可以很容易地使用 Data Annotations
public class Customer
{
public int Id { get; set; }
[StringLength(20)]
public string FirstName { get; set; }
public string LastName { get; set; }
}
就是这样。另一种方法可能是:
public class Customer
{
public int Id { get; set; }
private string firstName;
public string FirstName
{
get { return firstName }
set
{
if(value!=null && value.length<20)
{
firstName = value;
}
else
{
throw new ArgumentException("The first name must have at maxium 20 characters", "value");
}
}
}
public string LastName { get; set; }
}
考虑上述两种方法,但必须重新访问所有代码库并进行此检查。 crystal 显然属性获胜。
基本上是多余的。但是,如果它是关键任务,或者如果由于某种原因它造成了可怕的副作用,它可能会保留下来。很难说,但你的部分问题是 "can reflection change this value to null",答案是肯定的,可以在这个 linqpad 演示中看到
void Main()
{
var test = new Test();
test.Property = "5";
Console.WriteLine(test.Property);//5
FieldInfo fieldInfo = test.GetType().GetField("_property",BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(test, null);
Console.WriteLine(test.Property);//null
}
public class Test
{
private string _property = string.Empty;
public string Property
{
get { return _property; }
set { _property = value ?? string.Empty; }
}
}
是的,通过反射是可能的。不过,我不担心反射——人们使用反射来破坏你的设计 class 我不担心。
但是,我确实担心一件事:短语 "Assuming that _property is only set by the setter of Property" 是关键。您正在阻止 class 的用户将 属性 设置为空。
但是,您不能阻止您自己或您的 class 的其他维护者忘记仅使用您的 class 内部的 属性。事实上,你的例子有一些人从 class 内部检查字段而不是 属性 本身......这意味着,在你的 class 中,访问来自两个字段和 属性。
在大多数情况下(问题只能来自 class 内部)我会使用断言并断言该字段不为空。
如果我真的、真的、真的想确保它不为空(除非反思或人们一心想破坏东西),你可以尝试这样的事情:
internal class Program
{
static void Main()
{
string example = "Spencer the Cat";
UsesNeverNull neverNullUser = new UsesNeverNull(example);
Console.WriteLine(neverNullUser.TheString);
neverNullUser.TheString = null;
Debug.Assert(neverNullUser.TheString != null);
Console.WriteLine(neverNullUser.TheString);
neverNullUser.TheString = "Maximus the Bird";
Console.WriteLine(neverNullUser.TheString);
}
}
public class UsesNeverNull
{
public string TheString
{
get { return _stringValue.Value; }
set { _stringValue.Value = value; }
}
public UsesNeverNull(string s)
{
TheString = s;
}
private readonly NeverNull<string> _stringValue = new NeverNull<string>(string.Empty, str => str ?? string.Empty);
}
public class NeverNull<T> where T : class
{
public NeverNull(T initialValue, Func<T, T> nullProtector)
{
if (nullProtector == null)
{
var ex = new ArgumentNullException(nameof(nullProtector));
throw ex;
}
_value = nullProtector(initialValue);
_nullProtector = nullProtector;
}
public T Value
{
get { return _nullProtector(_value); }
set { _value = _nullProtector(value); }
}
private T _value;
private readonly Func<T, T> _nullProtector;
}
我知道这个问题很老了,但是你看,我需要我的一个字符串属性永远不会出现在 null 中。
所以我这样做了,它对我有用
public string Operation { get; set; } = string.Empty;
在这种方式下,默认值是一个空字符串,但绝不会为 null。
在重构代码时,我想到了如下实例
private string _property = string.Empty;
public string Property
{
set { _property = value ?? string.Empty); }
}
稍后在方法中我看到以下内容:
if (_property != null)
{
//...
}
假设_property
仅由Property
的setter设置,这段代码是不是多余?
也就是说,有什么办法可以通过反射魔法或其他方法使 _property
永远为空吗?
Assuming that _property is only set by the setter of Property, is this code redundant?
没错,就是多余的。这就是 Properties 的实际用途。我们不应该直接访问 class 的字段。我们应该使用 属性 访问它们。所以在相应的 setter 中,我们可以嵌入任何逻辑,我们可以放心,每次我们尝试设置一个值时,一旦 more.This 参数成立,即使对于 class。在方法中,我们必须使用属性而不是实际字段。此外,当我们要读取一个字段的值时,我们应该使用相应的getter。
一般来说,属性增强了封装的概念,这是面向对象编程 OOP 的支柱之一。
很多时候,当我们想要设置一个值时,没有任何逻辑可以应用。以下面的例子为例:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
我们已声明 class 代表客户。 Customer 对象应具有三个属性 Id
、FirstName
和 LastName
.
一个直接的问题,当有人读到这篇文章时 class 为什么有人要在这里使用属性?
答案还是一样的,他们提供了封装的机制。但是,让我们考虑一下这对长期 运行 有何帮助。假设有一天有人决定客户的名字应该是长度小于 20 的字符串。如果上面的 class 声明如下:
public class Customer
{
public int Id;
public string FirstName;
public string LastName;
}
那么我们应该在我们创建的每个实例中检查 FirstName
的长度!否则,如果我们选择了带有属性的声明,我们可以很容易地使用 Data Annotations
public class Customer
{
public int Id { get; set; }
[StringLength(20)]
public string FirstName { get; set; }
public string LastName { get; set; }
}
就是这样。另一种方法可能是:
public class Customer
{
public int Id { get; set; }
private string firstName;
public string FirstName
{
get { return firstName }
set
{
if(value!=null && value.length<20)
{
firstName = value;
}
else
{
throw new ArgumentException("The first name must have at maxium 20 characters", "value");
}
}
}
public string LastName { get; set; }
}
考虑上述两种方法,但必须重新访问所有代码库并进行此检查。 crystal 显然属性获胜。
基本上是多余的。但是,如果它是关键任务,或者如果由于某种原因它造成了可怕的副作用,它可能会保留下来。很难说,但你的部分问题是 "can reflection change this value to null",答案是肯定的,可以在这个 linqpad 演示中看到
void Main()
{
var test = new Test();
test.Property = "5";
Console.WriteLine(test.Property);//5
FieldInfo fieldInfo = test.GetType().GetField("_property",BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(test, null);
Console.WriteLine(test.Property);//null
}
public class Test
{
private string _property = string.Empty;
public string Property
{
get { return _property; }
set { _property = value ?? string.Empty; }
}
}
是的,通过反射是可能的。不过,我不担心反射——人们使用反射来破坏你的设计 class 我不担心。
但是,我确实担心一件事:短语 "Assuming that _property is only set by the setter of Property" 是关键。您正在阻止 class 的用户将 属性 设置为空。
但是,您不能阻止您自己或您的 class 的其他维护者忘记仅使用您的 class 内部的 属性。事实上,你的例子有一些人从 class 内部检查字段而不是 属性 本身......这意味着,在你的 class 中,访问来自两个字段和 属性。
在大多数情况下(问题只能来自 class 内部)我会使用断言并断言该字段不为空。
如果我真的、真的、真的想确保它不为空(除非反思或人们一心想破坏东西),你可以尝试这样的事情:
internal class Program
{
static void Main()
{
string example = "Spencer the Cat";
UsesNeverNull neverNullUser = new UsesNeverNull(example);
Console.WriteLine(neverNullUser.TheString);
neverNullUser.TheString = null;
Debug.Assert(neverNullUser.TheString != null);
Console.WriteLine(neverNullUser.TheString);
neverNullUser.TheString = "Maximus the Bird";
Console.WriteLine(neverNullUser.TheString);
}
}
public class UsesNeverNull
{
public string TheString
{
get { return _stringValue.Value; }
set { _stringValue.Value = value; }
}
public UsesNeverNull(string s)
{
TheString = s;
}
private readonly NeverNull<string> _stringValue = new NeverNull<string>(string.Empty, str => str ?? string.Empty);
}
public class NeverNull<T> where T : class
{
public NeverNull(T initialValue, Func<T, T> nullProtector)
{
if (nullProtector == null)
{
var ex = new ArgumentNullException(nameof(nullProtector));
throw ex;
}
_value = nullProtector(initialValue);
_nullProtector = nullProtector;
}
public T Value
{
get { return _nullProtector(_value); }
set { _value = _nullProtector(value); }
}
private T _value;
private readonly Func<T, T> _nullProtector;
}
我知道这个问题很老了,但是你看,我需要我的一个字符串属性永远不会出现在 null 中。
所以我这样做了,它对我有用
public string Operation { get; set; } = string.Empty;
在这种方式下,默认值是一个空字符串,但绝不会为 null。