.net 可以重构这个扩展方法吗?

.net 可以重构这个扩展方法吗?,.net,extension-methods,.net,Extension Methods,我有以下扩展方法: public static void ThrowIfArgumentIsNull<T>(this T value, string argument) where T : class { if (value == null) { throw new ArgumentNullException(argument); } } 工作100%良好 但是,我不喜欢我必须提供变量的名称,只是为了帮助我的异常消息 我想知道是否有

我有以下扩展方法:

public static void ThrowIfArgumentIsNull<T>(this T value, string argument) 
    where T : class
{
    if (value == null)
    {
        throw new ArgumentNullException(argument);
    }
}
工作100%良好

但是,我不喜欢我必须提供变量的名称,只是为了帮助我的异常消息

我想知道是否有可能重构扩展方法,所以可以这样调用它

qwerty.ThrowIfArgumentIsNull();
它会自动计算出变量的名称是'qwerty',因此使用它作为ArgumentNullException的值


可能吗?我假设反射可以做到这一点?

不,你不能这样做。这会很好,但如果没有某种AOP的参与,这是不可能的。我相信PostSharp可以做得很好,希望使用属性,在代码契约中它只是:

Contract.Requires(qwerty!=null);
理想情况下,我想要一个生成代码契约调用的PostSharp属性——我会在某个时候处理它——但在此之前,您拥有的扩展方法是我找到的最好的方法

(如果我曾经尝试过PostSharp+代码契约的方法,我肯定会在博客上写下它,顺便说一句……可能也会让它变得相当简单。)

编辑:要扩展Laurent的答案,您可能有:

new{qwerty}.CheckNotNull();
如果你有很多不可为空的参数,你可以:

new{qwerty,uiop,asdfg}.CheckNotNull();
这必须使用反射来计算属性。有一些方法可以避免在每次访问时进行反射,为每个属性构建一个委托,并通常使其变得时髦。我可能会调查这篇博文。。。但这有点令人讨厌,我更喜欢能够将参数属性化的想法

编辑:代码已执行,并已正式生成。是啊,但很有趣。

一句话:不


向扩展方法传递一个值。它不知道该值来自何处,也不知道调用方可能选择将其称为什么标识符。

我建议您执行以下操作:

public static void ThrowIfArgumentIsNull(this object value, string argument) 
{
    if (value == null)
    {
        throw new ArgumentNullException(argument);
    }
}
在这种情况下使用泛型似乎没有增加任何价值。但是关于你最初的问题,我认为那是不可能的

另请参见以获取完整的 解决方案与 回答

那么:

public void Save(Category qwerty)
{   
   ThrowIfArgumentIsNull( () => qwerty );
   qwerty.ThrowIfArgumentIsNull("qwerty");    
   // ....
}
然后将Throwifargumentisnall定义为

public static void ThrowIfArgumentIsNull(Expression<Func<object>> test)
{
   if (test.Compile()() == null)
   {
      // take the expression apart to find the name of the argument
   }
}
公共静态无效throwifargumentisnall(表达式测试)
{
if(test.Compile()()==null)
{
//将表达式拆分以查找参数的名称
}
}

很抱歉,我目前没有时间填写详细信息或提供完整的代码。

我发现使用代码片段最容易做到这一点

在您的示例中,我可以键入
tnaqwerty

以下是片段:

<?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>

检查空参数
tna
抛出新ArgumentNullException的代码段
渣
膨胀
周边地区
参数
检查空值的参数
价值


我喜欢看电视

基本语法:

Enforce.Arguments(() => controller, () => viewManager,() => workspace);

如果任何参数为null,这将引发参数名称和类型异常。

另请参见Check-blogged:)我认为这是一个非常简单问题的非常困难的解决方案。。。如果您使用的是Visual Studio,则可以使用代码段使此操作非常简单;)@Jeroen:您似乎认为问题在于类型,而不是防止重构,并将代码中的积垢量保持在最低限度。另请参见,您不需要lambda中的
return
部分。使用泛型允许方法排除值类型。注意
where T:class
我读了你的博客文章,你真的不必经历所有的喧嚣。只需实现一个不带参数的
ThrowIfNull()
方法,让堆栈跟踪开发人员在堆栈上走一走,找出哪个参数为null。只是想:)@RCIX,当抛出ArgumentNullException时,需要说出参数名。如果OP不关心标准,那么这就不是问题。请参阅API设计指南:@Jared:我查看了引发和处理错误部分以及ArgumentNullException类,但没有看到任何提及。
Enforce.Arguments(() => controller, () => viewManager,() => workspace);