Подтвердить что ты не робот

Можно ли реорганизовать этот метод расширения?

У меня есть следующий метод расширения:

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.

Возможные? Я предполагаю, что размышление может это сделать?

4b9b3361

Ответ 1

Нет, вы не можете этого сделать. Было бы неплохо, но это невозможно без участия какого-либо АОП. Я уверен, PostSharp может сделать хорошую работу, надеюсь, используя атрибуты, и в Code Contracts это будет просто:

Contract.Requires(qwerty != null);

В идеале мне нужен атрибут PostSharp, который генерирует вызов Code Contracts - и в какой-то момент я буду играть с ним, но до тех пор, у вас есть метод расширения, который я нашел...

(Если я когда-либо пробую подход PostSharp + Code Contracts, я обязательно буду об этом рассказывать, btw... Mono Cecil может сделать это достаточно легко.)

РЕДАКТИРОВАТЬ: Чтобы расширить ответ Лорана, вы могли бы иметь:

new { qwerty }.CheckNotNull();

И если у вас было много параметров, не имеющих значения NULL, вы могли бы:

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

Это должно было бы использовать отражение для разработки свойств. Есть способы, с помощью которых вы могли бы избежать отражения на каждом доступе, создавая делегат для каждого свойства и обычно делая его свистом. Я могу исследовать это для сообщения в блоге... но это несколько неприятно, и я предпочитаю, чтобы иметь возможность просто атрибутировать параметры...

EDIT: введен код и сообщение в блоге, сделанное должным образом. Ick, но весело

Ответ 2

Одним словом: нет.

Метод расширения передается значение. Он не знает, откуда взялось значение или какой идентификатор, который вызывающий может выбрать, чтобы ссылаться на него как.

Ответ 3

Мне проще всего это сделать, используя фрагмент кода.

В вашем примере я могу ввести 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

Я бы рекомендовал вам сделать следующее:

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

Использование дженериков в этом случае, похоже, не добавляет никакого значения. Но что касается вашего первоначального вопроса, я не думаю, что это возможно.

Ответ 5

См. также ArgumentNullException и рефакторинг для полного решений в тех же Ответ.

Как насчет:

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

Извините, у меня нет времени, чтобы заполнить деталь или предоставить полный код в настоящее время.

Ответ 6

Мне нравится Enforce из Lokad Shared Libraries.

Основной синтаксис:

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

Это вызовет исключение с именем параметра и введите, если любой из аргументов равен нулю.