目前我在一个名为“Ensure”的类中使用此代码,它本质上是一个静态方法的快捷类,用于使抛出异常更容易,所以我不是经常写出至少3要做一个例外的行,它总是可以在一行完成。
[DebuggerHidden, DebuggerStepThrough]
public static void ArgumentNotNull(object argument, string name)
{
if (argument == null)
{
throw new ArgumentNullException(name, "Cannot be null");
}
}
[DebuggerHidden, DebuggerStepThrough]
public static void ArgumentNotNull<T>(Expression<Func<T>> expr)
{
var e = (MemberExpression)expr.Body;
var val = GetValue<T>(e);
ArgumentNotNull(val, e.Member.Name);
}
我的问题是,目前在致电Ensure.ArgumentNotNull
时,我必须这样做:
Ensure.ArgumentNotNull(arg, "arg");
或
Ensure.ArgumentNotNull(() => arg);
因为我需要这个名称能够解释哪个参数在异常中引起了异常。
有没有办法能够在不需要lambda的ArgumentNotNull
部分的情况下调用() =>
并简单地调用Ensure.ArgumentNotNull(arg)
并且仍然能够获取该参数的名称通过,而不必专门传递名称。
答案 0 :(得分:2)
有没有办法能够在不需要lambda的
ArgumentNotNull
部分的情况下调用() =>
并简单地调用Ensure.ArgumentNotNull(arg)
并且仍然能够获取该参数的名称通过
我对此表示怀疑,因为值没有元数据来确定它是传入的参数,变量还是文字。价值并不总是一个论点 - 没有什么能阻止你调用Ensure.ArgumentNotNull(null);
。
答案 1 :(得分:1)
这是有效的
public static void ArgumentNotNull(object argument)
{
StackFrame stackFrame = new StackTrace(true).GetFrame(1);
string fileName = stackFrame.GetFileName();
int lineNumber = stackFrame.GetFileLineNumber();
var file = new System.IO.StreamReader(fileName);
for (int i = 0; i < lineNumber - 1; i++)
file.ReadLine();
string varName = file.ReadLine().Split(new char[] { '(', ')' })[1];
if (argument == null)
{
throw new ArgumentNullException(varName, "Cannot be null");
}
}
OP问题的替代答案
'and still be able to get the name of the argument that was passed, without having to specifically pass the name as well.'
简化的lamdba将成功。
myObject.ArgumentNotNull(x=>x.SomeProperty); -- prop checking
myObject.ArgumentNotNull(x=>x); -- objchecking
[DebuggerHidden, DebuggerStepThrough]
public static void ArgumentNotNull<T>(this T obj, Expression<Func<T, object>> expr = null)
{
if (obj == null) throw new NullReferenceException();
var body = expr.Body as MemberExpression;
if (body == null)
{
var ubody = (UnaryExpression)expr.Body;
body = ubody.Operand as MemberExpression;
}
if (body != null)
{
var property = body.Member as PropertyInfo;
if (property == null) throw;
if (obj.GetType().GetProperty(property.Name).GetValue(obj, null) == null) throw new NullReferenceException();
}
else
{
var ubody = (UnaryExpression)expr.Body;
var property = ubody.Operand as MemberExpression;
if (property != null)
props[property.Member.Name] = obj.GetType()
.GetProperty(property.Member.Name)
.GetValue(obj, null);
if (obj.GetType().GetProperty(property.Member.Name).GetValue(obj, null) == null) throw new NullReferenceException();
}
}
答案 2 :(得分:0)
如果您在调用throw new ArgumentNullException("argName");
时担心出错,那么您真的想使用Fody.NullGuard而不是当前的解决方案。
你像这样使用Fody.NullGuard
public class Sample
{
public void SomeMethod(string arg)
{
// throws ArgumentNullException if arg is null.
}
public void AnotherMethod([AllowNull] string arg)
{
// arg may be null here
}
}
编译完成后,Fody将重写IL,因此其功能与
相同public class Sample
{
public void SomeMethod(string arg)
{
if(arg == null)
throws new ArgumentNullException("arg");
}
public void AnotherMethod(string arg)
{
}
}
答案 3 :(得分:0)
除了Aron提到的Fody.NullGuard(仅选择退出模型)和其他AOP框架(PostSharp)之外,我不知道你可以使用任何机制,除非有一定程度的代码混乱。
但是,您可以使用匿名类型,而不是使用表达式树,它们都会导致显着的运行时性能损失并且在语法方面受到限制。这种方法在性能方面相对较好,有几个假设:
API的用法如下所示:
void SomeMethod(object arg1, string arg2, List<int> arg3)
{
new { arg1, arg2, arg3 }.ShouldNotBeNull();
....
实施太大而无法在此处显示,因此可以在this gist中找到。此外,它还可以扩展到范围验证等。