Можно ли реорганизовать этот метод расширения?
У меня есть следующий метод расширения:
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.
Возможные? Я предполагаю, что размышление может это сделать?
Ответы
Ответ 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);
Это вызовет исключение с именем параметра и введите, если любой из аргументов равен нулю.