第一次学习C#时,我很惊讶他们在宏的支持上没有像C / C ++中那样的能力。我知道C#中存在#define关键字,但与我在C / C ++中所钟爱的相比,它大大缺乏。 有人知道为什么真正的宏在C#中不见了吗?
如果类似问题已经被提出,我向您道歉-我保证我花了足足5分钟的时间寻找重复问题。
第一次学习C#时,我很惊讶他们在宏的支持上没有像C / C ++中那样的能力。我知道C#中存在#define关键字,但与我在C / C ++中所钟爱的相比,它大大缺乏。 有人知道为什么真正的宏在C#中不见了吗?
如果类似问题已经被提出,我向您道歉-我保证我花了足足5分钟的时间寻找重复问题。
来自 C# 常见问题解答。
http://blogs.msdn.com/CSharpFAQ/archive/2004/03/09/86979.aspx
为什么 C# 不支持 #define 宏?
在 C++ 中,我可以定义一个宏:
#define PRODUCT(x, y, z) x * y * z
然后在代码中使用它:
int a = PRODUCT(3, 2, 1);
C# 不允许你这样做。为什么?
其中一些原因是可读性问题。
C# 的主要设计目标之一是保持代码的可读性。拥有编写宏的能力使程序员能够创建自己的语言——这种语言不一定与底层代码相关。为了理解代码的作用,用户不仅必须了解语言的工作原理,还必须了解当前生效的所有 #define 宏。这使得代码更难以阅读。
在 C# 中,您可以使用方法代替宏,在大多数情况下,JIT 将内联它们,使您具有相同的性能方面。
还有一个比较微妙的问题。宏是以文本形式完成的,这意味着如果我写:
int y = PRODUCT (1 + 2, 3 + 4, 5 + 6)
我期望得到的是
3 * 7 *11 = 231
的结果,但实际上,根据我定义的展开式,结果是:
int y = 1 + 2 * 3 + 4 * 5 + 6;
33这个问题可以通过巧妙地使用括号来解决,但很容易编写一个只在某些情况下起作用的宏。虽然C#严格来说没有预处理器,但它具有条件编译符号可用于影响编译。这些符号可以在代码中定义或通过编译器参数定义。C#中的“预处理”指令(仅因与C/C++一致而命名为此,尽管没有单独的预处理步骤)如下所示:
#define 和 #undef
用于定义和取消定义条件编译符号
#if、#elif、#else 和 #endif
用于有条件地跳过源代码段
#line
用于控制错误和警告发出时的行号。
#error 和 #warning
用于发出错误和警告。
#region 和 #endregion
用于明确标记源代码段。
有关上述内容的更多信息,请参见ECMA规范书第9.5节。还可以使用方法上的Conditional属性实现条件编译,以便当适当的符号被定义时,对该方法的调用将仅被编译。有关此功能的更多信息,请参见ECMA规范书第24.4.2节。
作者:Eric Gunnerson
这样你就可以一遍又一遍地快乐地输入“THIS”了。
// Windows presetation foundation dependency property.
public class MyStateControl : ButtonBase
{
public MyStateControl() : base() { }
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
"State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}
很明显,C#和.NET的设计师从未真正使用过他们创建的库或框架。如果他们这样做了,他们就会意识到一些形式的卫生宏系统肯定是必要的。
不要让C和C++的弱小宏使您对编译时解析代码的强大功能失去信心。编译时解析和代码生成允许您更有效地表达代码的含义和意图,而无需拼写源代码的所有琐碎细节。例如,如果您可以用下面的代码替换上面的代码:
public class MyStateControl : ButtonBase
{
public MyStateControl() : base() { }
[DependencyProperty(DefaultValue=true)]
bool State { get; set; }
}
Boo 使用它们,OcamML (至少是 Meta ML)也使用它们,C 和 C++ 也使用它们(尽管是以不太友好的形式,但总比根本没有强)。C# 则没有。
C#的目标受众比C++、C或汇编更广泛(或用其他术语说,是消费者基础)。实现这一目标的唯一方法是吸引技能较差的程序员。因此,所有强大但危险的工具都被取走了。例如,宏,多重继承,控制对象生命周期或类型不透明编程。
同样地,火柴、刀子和钉枪也很有用和必要,但它们必须放在儿童拿不到的地方。(不幸的是,纵火、谋杀、内存泄漏和难以阅读的代码仍然会发生)。
在指责我不懂C#之前,你写了多少次这样的代码:
protected int _PropOne;
public int PropOne
{
get
{
return _PropOne;
}
set
{
if(value == _PropOne) { return; }
NotifyPropertyChanging("PropOne");
_PropOne = value;
NotifyPropertyChanged("PropOne");
}
}
使用宏时,这16行的每次出现都会像这样:
DECLARE_PROPERTY(int, PropOne)
DECLARE_PROPERTY(string, PropTwo)
DECLARE_PROPERTY(BitmapImage, PropThree)
C/C++中的宏常量被用来定义常量、生成小型内联函数以及与编译代码直接相关的各种事情(如#ifdef)。
在C#中,您有强类型常量,足够智能的编译器可以在必要时内联函数,并且知道如何以正确的方式编译代码(没有预编译头文件的荒谬)。
但是,如果您真的想这样做的话,也没有特别的理由不先通过C预处理器运行您的CS文件 :)
http://lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html
比我更勇敢的人已经在C#中自己构建了类似的宏系统http://www.codeproject.com/KB/recipes/prepro.aspx
任何认同宏定义不好的观点的人都应该读一下《双手合十》这本书。http://en.wikipedia.org/wiki/With_Folded_Hands 这本书讲述了一个故事,告诉我们如何防止人们做傻事,甚至到了防止他们做明智之举的地步。
虽然我喜欢C#,但我真的很讨厌它对实际软件工程师的愚蠢化贡献。所以,是的,把宏定义留给专业人士吧。顺便说一下,变量的命名也应该留给专业人士。否则会导致代码难以阅读。为了遵循“代码必须最终可读”的完整声明,所有变量都应该按A-Z、a-z(或其他任意构造,比如只使用名词)进行命名。因为有些不熟练的人可能会将其变量命名为“SomethingUsefulButNotAllowedByTheCompilerBecauseSomeUsersMayDoDumbThings”。
宏是一个工具,用于那些大多数程序员比编译器聪明的日子。在C/C++中,仍然有一些情况是正确的。
如今,大多数程序员都没有C#编译器/运行时聪明。
#define
作为文件中的第一项;3)不会将指令“泄漏”到其他文件中。 - Sam Harwell