为什么条件方法的参数总是类型检查?
Why are the arguments to a Conditional method always type-checked?
如果条件方法被编译掉,每次调用的参数仍会在编译时进行类型检查。这样做的动机是什么?示例:
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) { }
}
}
明确地说,条件符号 "condition" 未在此上下文中定义,因此编译生成的 MSIL 中省略了方法调用。这与 here 定义的规范不相上下,因此不足为奇。想象一个更复杂的场景:
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
}
}
只有在定义了条件符号 "condition" 时,对 'ConditionalMethod' 的调用才会包含在生成的编译中。然而,在那种情况下,Bar 实际上可以向上转换为 Foo。如果编译器知道对 'ConditionalMethod' 的调用将被编译掉,难道它不应该也知道如果我们关心此方法的调用,此代码将是合法的吗?是的,这是一个人为的、令人毛骨悚然的例子,但它有助于说明我的问题。我问是出于良性的好奇心,因为这已经让我烦恼了很长一段时间。请帮忙,乔恩双向飞碟。 :)
想象一下这段代码
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) { }
}
方法的签名是将调用与应调用的方法相关联的关键部分。在知道条件属性是否适用之前,必须建立该关联。在上面的示例中,调用不匹配任何方法。编译器必须大胆猜测你 的意思是 Blah(int,string)。但这是一个猜测,因为签名不匹配(参数类型的顺序错误)。 Blah(string,int,int) 也很接近——你只是忘记了一个参数。 Blahh(string,int) 也很接近——你只是在名字中打错了字。
有关类似示例,请参阅 this blog post by Eric Lippert(谁知道这东西)。
Therefore the arguments must be well-defined at the point of the call,
even if the call is going to be removed. In fact, the call cannot be
removed unless the arguments are extant!
以后
The effect of a conditional compilation directive happens at lex time;
anything that is inside a removed #if block is treated by the lexer as
a comment. It’s like you simply deleted the whole contents of the
block and replaced it with whitespace. But removal of call sites
depending on conditional attributes happens at semantic analysis time;
everything necessary to perform that semantic analysis must be
present.
如果条件方法被编译掉,每次调用的参数仍会在编译时进行类型检查。这样做的动机是什么?示例:
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) { }
}
}
明确地说,条件符号 "condition" 未在此上下文中定义,因此编译生成的 MSIL 中省略了方法调用。这与 here 定义的规范不相上下,因此不足为奇。想象一个更复杂的场景:
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
}
}
只有在定义了条件符号 "condition" 时,对 'ConditionalMethod' 的调用才会包含在生成的编译中。然而,在那种情况下,Bar 实际上可以向上转换为 Foo。如果编译器知道对 'ConditionalMethod' 的调用将被编译掉,难道它不应该也知道如果我们关心此方法的调用,此代码将是合法的吗?是的,这是一个人为的、令人毛骨悚然的例子,但它有助于说明我的问题。我问是出于良性的好奇心,因为这已经让我烦恼了很长一段时间。请帮忙,乔恩双向飞碟。 :)
想象一下这段代码
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) { }
}
方法的签名是将调用与应调用的方法相关联的关键部分。在知道条件属性是否适用之前,必须建立该关联。在上面的示例中,调用不匹配任何方法。编译器必须大胆猜测你 的意思是 Blah(int,string)。但这是一个猜测,因为签名不匹配(参数类型的顺序错误)。 Blah(string,int,int) 也很接近——你只是忘记了一个参数。 Blahh(string,int) 也很接近——你只是在名字中打错了字。
有关类似示例,请参阅 this blog post by Eric Lippert(谁知道这东西)。
Therefore the arguments must be well-defined at the point of the call, even if the call is going to be removed. In fact, the call cannot be removed unless the arguments are extant!
以后
The effect of a conditional compilation directive happens at lex time; anything that is inside a removed #if block is treated by the lexer as a comment. It’s like you simply deleted the whole contents of the block and replaced it with whitespace. But removal of call sites depending on conditional attributes happens at semantic analysis time; everything necessary to perform that semantic analysis must be present.