Почему аргументы к условному методу всегда проверяются типом?
В случае, если условный метод компилируется, аргументы каждого вызова все еще проверяются на тип во время компиляции. Какова мотивация для этого? Пример:
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int x = 2;
string st = "";
// this invocation compiles fine
ConditionalMethod(x, st);
// this invocation won't compile
ConditionalMethod(st, x);
}
[Conditional("condition")]
public static void ConditionalMethod(int x, string st) { }
}
}
Чтобы было ясно, условный символ "условие" не определен в этом контексте, поэтому вызовы метода опускаются из MSIL в результате компиляции. Это на уровне спецификации, определенной здесь, так что никаких сюрпризов. Представьте себе более сложный сценарий:
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ConditionalMethod(new Bar());
}
[Conditional("condition")]
public static void ConditionalMethod(Foo foo) { }
public class Foo { }
#if condition
public class Bar : Foo { }
#else
public class Bar { }
#endif
}
}
Вызовы "ConditionalMethod" будут включены в результирующую компиляцию только тогда, когда определен условный символ "условие". В этом случае, однако, Бар МОЖЕТ быть фактически передан в Foo. Если компилятор знает, что вызовы ConditionalMethod будут скомпилированы, разве не следует также знать, что в случае, если мы заботимся о вызовах этого метода, этот код будет допустимым? Да, это надуманный и потрясающий пример, но он помогает проиллюстрировать мой вопрос. Я прошу из любезного любопытства, поскольку это раздражало меня в течение довольно долгого времени. Пожалуйста, помогите, Джон Скит.:)
1 ответ
Представьте себе этот код
class Program
{
static void Main(string[] args)
{
int x = 2;
string st = "";
// this invocation compiles fine
Blah(x, st);
// this invocation won't compile
Blah(st, x);
}
[Conditional("condition")]
public static void Blah(int x, string st) { }
public static void Blah (string st, int x, int y) { }
public static void Blahh(string st, int x) { }
}
Подпись метода является важной частью связи вызова метода, который должен быть вызван. Эта связь должна быть сделана до того, как станет известно, применяется ли атрибут Conditional. В приведенном выше примере вызов не соответствует ни одному из методов. Компилятор должен сделать прыжок в веру, чтобы догадаться, что вы имели в виду Blah (int, string). Но это было бы предположение, потому что подпись не совпадает (типы аргументов в неправильном порядке). Blah (string, int, int) также довольно близок - вы просто забыли аргумент. И Blahh (string, int) тоже близко - вы только что сделали опечатку в названии.
Для подобного примера, см. Этот пост Эрика Липперта (который знает это).
Поэтому аргументы должны быть четко определены в точке вызова, даже если вызов будет удален. Фактически, вызов не может быть удален, если аргументы не существуют!
и позже
Эффект директивы условной компиляции происходит в течение времени lex; все, что находится внутри удаленного блока #if, рассматривается лексером как комментарий. Как будто вы просто удалили все содержимое блока и заменили его пробелами. Но удаление сайтов вызовов в зависимости от условных атрибутов происходит во время семантического анализа; все необходимое для выполнения этого семантического анализа должно присутствовать.