重载构造函数时如何避免 NullReferenceException?
How can I avoid NullReferenceException when overloading the constructor?
为了更好地说明我的情况,我编了个例子
void Main()
{
var a = new Lol(null);
}
public class Lol
{
public Lol(string a, string b)
{
if(a == null || b == null)
{
throw new Exception();
}
}
public Lol(Tuple<string, string> k)
: this(k.Item1, k.Item2)
{
}
}
在这种情况下,我在第二个构造函数中得到一个 NullReferenceException
。有没有办法从方法内部处理它,保持相同的结构,或者我应该创建一个私有方法并让两个构造函数都调用这个方法?
这是设计使然,您需要在第二个构造函数中进行检查
public Lol(Tuple<string, string> k)
{
if(k == null || k.Item1 == null || k.Item2 == null)
{
throw new Exception();
}
}
您可以将逻辑抽象为辅助方法,并让两个构造函数都调用辅助方法。
public class Lol
{
public Lol(string a, string b)
{
LolHelper(a, b);
}
public Lol(Tuple<string, string> k)
{
(k!=null)
?LolHelper(k.Item1, k.Item2)
:LolHelper(null, null);
}
private void LolHelper(string a, string b)
{
if(a == null || b == null)
{
throw new Exception();
}
}
}
在不改变任何逻辑的情况下,你可以这样做:
public class Lol
{
public Lol(string a, string b)
{
if(a == null || b == null)
{
throw new Exception();
}
}
public Lol(Tuple<string, string> k)
: this(k != null ? k.Item1 : null, k != null ? k.Item2 : null)
{
}
}
然而,在更复杂的情况下,这可能不起作用(尽管无论如何您都不应该在构造函数链中放置任何复杂的逻辑)。
这应该适用于带有 C#6 的 VS2015:
this(k?.Item1, k?.Item2)
最后:
void Main()
{
var a = new Lol(null);
}
public class Lol
{
public Lol(string a, string b)
{
if(a == null || b == null)
throw new Exception();
}
public Lol(Tuple<string, string> k)
: this(k?.Item1, k?.Item2)
{
}
}
首先不在构造函数中传递 null。如果您希望对应于 a 和 b 的字段或属性为空,只需将其放入构造函数中,如下所示:
private string a;
private string b;
public Lol()
{
a= null;
b= null;
}
在 Main() 中使用:
var a = new Lol();
如果要传递值而不是 null,请使用适当的构造函数。
我的方法是扩展方法:
public static class Requirements
{
public static T NotNull<T>(this T value, string parameterName, string message)
where T : class =>
value ?? throw new ArgumentNullException(parameterName, message);
public static T NotNull<T>(this T value, string parameterName)
where T : class =>
value ?? throw new ArgumentNullException(parameterName);
}
用法:
public class Lol
{
public Lol(string a, string b)
{
if(a == null || b == null)
{
throw new ArgumentNullException();
}
}
public Lol(Tuple<string, string> k)
: this(k.NotNull(nameof(k)).Item1, k.NotNull(nameof(k)).Item2)
{
}
}
为了更好地说明我的情况,我编了个例子
void Main()
{
var a = new Lol(null);
}
public class Lol
{
public Lol(string a, string b)
{
if(a == null || b == null)
{
throw new Exception();
}
}
public Lol(Tuple<string, string> k)
: this(k.Item1, k.Item2)
{
}
}
在这种情况下,我在第二个构造函数中得到一个 NullReferenceException
。有没有办法从方法内部处理它,保持相同的结构,或者我应该创建一个私有方法并让两个构造函数都调用这个方法?
这是设计使然,您需要在第二个构造函数中进行检查
public Lol(Tuple<string, string> k)
{
if(k == null || k.Item1 == null || k.Item2 == null)
{
throw new Exception();
}
}
您可以将逻辑抽象为辅助方法,并让两个构造函数都调用辅助方法。
public class Lol
{
public Lol(string a, string b)
{
LolHelper(a, b);
}
public Lol(Tuple<string, string> k)
{
(k!=null)
?LolHelper(k.Item1, k.Item2)
:LolHelper(null, null);
}
private void LolHelper(string a, string b)
{
if(a == null || b == null)
{
throw new Exception();
}
}
}
在不改变任何逻辑的情况下,你可以这样做:
public class Lol
{
public Lol(string a, string b)
{
if(a == null || b == null)
{
throw new Exception();
}
}
public Lol(Tuple<string, string> k)
: this(k != null ? k.Item1 : null, k != null ? k.Item2 : null)
{
}
}
然而,在更复杂的情况下,这可能不起作用(尽管无论如何您都不应该在构造函数链中放置任何复杂的逻辑)。
这应该适用于带有 C#6 的 VS2015:
this(k?.Item1, k?.Item2)
最后:
void Main()
{
var a = new Lol(null);
}
public class Lol
{
public Lol(string a, string b)
{
if(a == null || b == null)
throw new Exception();
}
public Lol(Tuple<string, string> k)
: this(k?.Item1, k?.Item2)
{
}
}
首先不在构造函数中传递 null。如果您希望对应于 a 和 b 的字段或属性为空,只需将其放入构造函数中,如下所示:
private string a;
private string b;
public Lol()
{
a= null;
b= null;
}
在 Main() 中使用:
var a = new Lol();
如果要传递值而不是 null,请使用适当的构造函数。
我的方法是扩展方法:
public static class Requirements
{
public static T NotNull<T>(this T value, string parameterName, string message)
where T : class =>
value ?? throw new ArgumentNullException(parameterName, message);
public static T NotNull<T>(this T value, string parameterName)
where T : class =>
value ?? throw new ArgumentNullException(parameterName);
}
用法:
public class Lol
{
public Lol(string a, string b)
{
if(a == null || b == null)
{
throw new ArgumentNullException();
}
}
public Lol(Tuple<string, string> k)
: this(k.NotNull(nameof(k)).Item1, k.NotNull(nameof(k)).Item2)
{
}
}