我有以下扩展方法:
public static void ThrowIfArgumentIsNull<T>(this T value, string argument)
where T : class
{
if (value == null)
{
throw new ArgumentNullException(argument);
}
}
这是它的用法示例......
// Note: I've poorly named the argument, on purpose, for this question.
public void Save(Category qwerty)
{
qwerty.ThrowIfArgumentIsNull("qwerty");
....
}
100%罚款。
但是,我不喜欢我必须提供变量的名称,只是为了帮助我的异常消息。
我想知道是否可以重构扩展方法,所以它可以这样调用......
qwerty.ThrowIfArgumentIsNull();
并自动指出变量的名称是'qwerty',因此将其用作ArgumentNullException的值。
可能?我假设反思可以做到这一点?
答案 0 :(得分:34)
不,你不能这样做。这会很好,但如果没有某种AOP参与,这是不可能的。我确信PostSharp可以做得很好,希望使用属性,而在Code Contracts中它只是:
Contract.Requires(qwerty != null);
理想情况下,我想要一个生成Code Contracts调用的PostSharp属性 - 我会在某个时候使用它 - 但在那之前,你所获得的扩展方法是我发现的最佳方法。 ..
(如果我尝试过PostSharp + Code Contracts方法,我肯定会在博客上发表文章,顺便说一句...... Mono Cecil也可能会让它变得相当简单。)
编辑:要扩展Laurent的答案,您可能会:
new { qwerty }.CheckNotNull();
如果你有很多不可为空的参数,你可以:
new { qwerty, uiop, asdfg }.CheckNotNull();
这必须使用反射来计算属性。有些方法可以避免对每个访问进行反射,为每个属性构建一个委托,并且通常会使其变得眩目。我可能会对博客文章进行调查......但它有些蠢,而且我更喜欢能够将参数归因于......
编辑:代码已实施,blog post正式制作。 Ick,但很有趣
答案 1 :(得分:3)
总之:不。
扩展方法传递一个值。它不知道值来自何处或调用者可能选择将其称为什么标识符。
答案 2 :(得分:2)
我发现使用代码段最容易做到这一点。
在您的示例中,我可以输入tna<tab>qwerty<enter>
。
以下是摘录:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Check for null arguments</Title>
<Shortcut>tna</Shortcut>
<Description>Code snippet for throw new ArgumentNullException</Description>
<Author>SLaks</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
<SnippetType>SurroundsWith</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>Parameter</ID>
<ToolTip>Paremeter to check for null</ToolTip>
<Default>value</Default>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[if ($Parameter$ == null) throw new ArgumentNullException("$Parameter$");
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
答案 3 :(得分:1)
我建议你做以下事情:
public static void ThrowIfArgumentIsNull(this object value, string argument)
{
if (value == null)
{
throw new ArgumentNullException(argument);
}
}
在这种情况下使用泛型似乎没有添加任何值。但至于你原来的问题,我认为这是不可能的。
答案 4 :(得分:1)
另见ArgumentNullException and refactoring完整版 与...相同的解决方案 答案。
怎么样:
public void Save(Category qwerty)
{
ThrowIfArgumentIsNull( () => return qwerty );
qwerty.ThrowIfArgumentIsNull("qwerty");
// ....
}
然后将ThrowIfArgumentIsNull定义为
public static void ThrowIfArgumentIsNull(Expression<Func<object>> test)
{
if (test.Compile()() == null)
{
// take the expression apart to find the name of the argument
}
}
抱歉,我没有时间填写详细信息或提供目前的完整代码。
答案 5 :(得分:1)
我喜欢Enforce中的Lokad Shared Libraries。
基本语法:
Enforce.Arguments(() => controller, () => viewManager,() => workspace);
如果任何参数为null,这将引发参数名称和类型的异常。