代码之家  ›  专栏  ›  技术社区  ›  Pure.Krome

是否可以重构此扩展方法?

  •  27
  • Pure.Krome  · 技术社区  · 15 年前

    我有以下扩展方法:

    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的值。

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

    6 回复  |  直到 10 年前
        1
  •  34
  •   Jon Skeet    10 年前

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

    Contract.Requires(qwerty != null);
    

    理想情况下,我想要一个PostSharp属性来生成代码契约调用——我会在某个时候处理它——但是在那之前,您得到的扩展方法是我找到的最好的方法……

    (如果我尝试过PostSharp+代码契约方法,我肯定会在博客上介绍它,顺便说一句… Mono Cecil 可能也会变得相当容易。)

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

    new { qwerty }.CheckNotNull();
    

    如果你有很多不可以为空的参数,你可以有:

    new { qwerty, uiop, asdfg }.CheckNotNull();
    

    这需要使用反射来计算属性。有一些方法可以避免对每个访问进行反射,为每个属性构建一个委托,并且通常会使它变得很出色。我可能会调查这个博客帖子…但这有点恶心,我更喜欢能将参数属性化的想法…

    编辑:代码实现,以及 blog post 正式制作。但有趣

        2
  •  3
  •   AnthonyWJones    15 年前

    总之:没有。

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

        3
  •  2
  •   SLaks    15 年前

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

    在您的示例中,我可以键入 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>
    
        4
  •  1
  •   Jaco Pretorius    15 年前

    我建议您最好执行以下操作:

    public static void ThrowIfArgumentIsNull(this object value, string argument) 
    {
        if (value == null)
        {
            throw new ArgumentNullException(argument);
        }
    }
    

    在这种情况下使用泛型似乎没有增加任何价值。但关于你最初的问题,我认为那是不可能的。

        5
  •  1
  •   Ian Ringrose    15 年前

    也见 ArgumentNullException and refactoring 为了一个完整的 解决方案与 回答。

    如何:

    public void Save(Category qwerty)
    {   
       ThrowIfArgumentIsNull( () => return qwerty );
       qwerty.ThrowIfArgumentIsNull("qwerty");    
       // ....
    }
    

    然后将throwifargumentInstall定义为

    public static void ThrowIfArgumentIsNull(Expression<Func<object>> test)
    {
       if (test.Compile()() == null)
       {
          // take the expression apart to find the name of the argument
       }
    }
    

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

        6
  •  1
  •   Nick Cox Hans Z.    15 年前

    我喜欢 Enforce Lokad Shared Libraries .

    基本语法:

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

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

    推荐文章