为什么 C# 中没有宏?

发布于 2024-08-03 14:40:56 字数 202 浏览 6 评论 0原文

当第一次学习 C# 时,我很惊讶他们不支持与 C/C++ 中相同的宏。我意识到 C# 中存在#define 关键字,但与我逐渐喜欢的 C/C++ 中的关键字相比,它是非常缺乏的。有谁知道为什么 C# 中缺少 real 宏?

如果这个问题已经以某种形式提出,我深表歉意 - 我保证在发布之前我花了整整 5 分钟寻找重复项。

When learning C# for the first time, I was astonished that they had no support for macros in the same capacity that exists in C/C++. I realize that the #define keyword exists in C#, but it is greatly lacking compared to what I grew to love in C/C++. Does anyone know why real macros are missing from C#?

I apologize if this question is already asked in some form or another - I promise I spent a solid 5 minutes looking for duplicates before posting.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

我偏爱纯白色 2024-08-10 14:40:57

这样您就可以一遍又一遍地输入此内容并获得乐趣。

// 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# 没有。

So that you can have fun typing THIS over and over and over again.

// 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));
}

Obviously the designers of C# and .NET never actually use any of the libraries or frameworks they create. If they did, they would realize that some form of hygenic syntactic macro system is definitely in order.

Don't let the shortcomings of C and C++'s lame macros sour you on the power of compile time resolved code. Compile time resolution and code generation allows you to more effectively express the MEANING and INTENT of code without having to spell out all of the niggling details of the source code. For example, what if you could replace the above with this:

public class MyStateControl : ButtonBase
{
  public MyStateControl() : base() { }

  [DependencyProperty(DefaultValue=true)] 
  bool State { get; set; }
}

Boo has them, OcamML (at least Meta ML) has them, and C and C++ has them (in a nasty form, but better than not having them at all). C# doesn't.

我不吻晚风 2024-08-10 14:40:57

根据我的经验,C++ 风格的宏增加了大量的复杂性,但没有相应的好处。我当然没有错过 C# 或 Java 中的它们。 (我很少在 C# 中使用预处理器符号,但我偶尔很高兴它们的存在。)

现在,很多人都呼吁使用 Lisp 风格的宏,我对此知之甚少,但听起来肯定比 C++ 风格的宏更令人愉快。

您特别想用宏来做什么?我们也许能够帮助您以更惯用的 C# 方式思考......

C++-style macros add a huge amount of complexity without corresponding benefit, in my experience. I certainly haven't missed them either in C# or Java. (I rarely use preprocessor symbols at all in C#, but I'm occasionally glad they're there.)

Now various people have called for Lisp-style macros, which I know little about but certainly sound rather more pleasant than C++-style ones.

What do you particularly want to do with macros? We may be able to help you think in a more idiomatically C# way...

手心的海 2024-08-10 14:40:57

C# 的目标受众比 C++、C 或 ASM 更广泛(或者换句话说,消费者基础)。实现这一目标的唯一方法是接触技能水平相当低的程序员。因此,所有强大但危险的工具都被拿走了。即宏、多重继承、对对象生命周期的控制或类型不可知的编程。

同样,火柴、刀和射钉枪都是有用且必要的,但必须将它们放在儿童接触不到的地方。 (可悲的是,纵火、谋杀、内存泄漏和不可读的代码仍然会发生)。

在指责我不考虑 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# is aimed at wider audience (or in other term, consumer base) than C++, C or ASM. The only way of achieving this goal is reaching programmers considerably less skilled. Therefore, all the powerful but dangerous tools are taken away. I.e. macros, multiple inheritance, control over object lifetime or type-agnostic programming.

In a very same way matches, knives and nailguns are useful and necessary, but they have to be kept out of reach of children. (sadly, arsons, murders, memory leaks and unreadable code still do happen).

And before accusing me of not thinking C#, how many times have you wrote that:

protected int _PropOne;
public int PropOne
{
    get
    {
        return _PropOne;
    }
    set
    {
        if(value == _PropOne) { return; }
        NotifyPropertyChanging("PropOne");
        _PropOne = value;
        NotifyPropertyChanged("PropOne");
    }
}

With macros, every time those 16 lines would look like that:

DECLARE_PROPERTY(int, PropOne)
DECLARE_PROPERTY(string, PropTwo)
DECLARE_PROPERTY(BitmapImage, PropThree)
怎言笑 2024-08-10 14:40:57

C / C++ 中的宏用于定义常量、生成小型内联函数以及与编译代码直接相关的各种操作 (#ifdef)。

在 C# 中,您拥有强类型常量、足够智能的编译器,可以在必要时内联函数,并且知道如何以正确的方式编译内容(没有预编译头废话)。

但是,如果您确实想要的话,没有什么特殊原因不能首先通过 C 预处理器运行 CS 文件:)

Macros in C / C++ were used to define constants, produce small inline functions, and for various things directly related to compiling the code (#ifdef).

In C#, you have strongly typed constants, a smart enough compiler to inline functions when necessary, and knows how to compile stuff the right way (no precompiled header nonsense).

But there's no particular reason why you couldn't run your CS file through the C preprocessor first if you really wanted to :)

过气美图社 2024-08-10 14:40:57

作为一名长期学习 C++ 的 C# 程序员,我现在怀念对 C# 元编程的丰富支持。至少,我现在对元编程的含义有了更广泛的认识。

我真的很希望看到 C# 中的 Nemerle 所提供的宏支持。似乎给语言添加了一种非常自然且强大的扩展能力。如果您还没有看过,我强烈建议您这样做。

维基百科上有一些很好的例子。

As a long time C# programmer who went off to learn C++ for a while, I now miss rich support for metaprogramming C#. At least, I now have a more expansive appreciation for what metaprogramming can mean.

I would really like to see the kind of macro support that's instilled in Nemerle in C#. It seems to add a very natural and powerful extension capability to the language. If you haven't looked at it, I really recommend doing so.

There are some great examples on Wikipedia.

遥远的她 2024-08-10 14:40:57

宏在C++中被过度使用,但它们仍然有它们的用途 ,但是由于反射和错误报告异常的更好集成使用,大多数这些用途在 C# 中并不相关。

Macros are overused in C++ but they still have their uses, however most of these uses are not relevant in C# due to reflection and the better integrated use of exceptions for error reporting.

祁梦 2024-08-10 14:40:57

本文比较了 perl 和 lisp 宏,但要点仍然相同:与源代码级宏 (lisp) 相比,文本级宏 (perl/c++) 会导致大量问题

http://lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html

勇敢的人比我已经在 C# 中推出了自己的宏系统 http://www.codeproject.com/ KB/recipes/prepro.aspx

This article compares perl and lisp macros but the point is still the same: Text level macros (perl/c++) cause massive problems compared to source level macros (lisp)

http://lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html

Braver people than me have rolled their own macro like system in c# http://www.codeproject.com/KB/recipes/prepro.aspx

倾城月光淡如水﹏ 2024-08-10 14:40:57

在大多数程序员比编译器更聪明的时代,宏是一种工具。在 C/C++ 中,仍有一些情况是这样的。

如今,大多数程序员并不像 C# 编译器/运行时那么聪明。

Macros are a tool for the days when most programmers were smarter than the compiler. In C/C++, there are still some cases where this is true.

Nowdays, most programmers aren't as smart as the C# compiler/runtime.

寄人书 2024-08-10 14:40:57

任何同意宏不好这一观点的人都应该阅读《双手合十》一书。 http://en.wikipedia.org/wiki/With_Folded_Hands 它讲述了一个关于我们如何能够阻止人们做愚蠢的事情,甚至阻止他们做非常明智的事情。

虽然我喜欢 C#,但我真的很讨厌它让实际软件工程师变得愚蠢。所以,是的,把宏留给专业人士。当我们这样做时,也将变量的命名留给专业人士。这可能会导致一些非常不可读的代码。为了遵循“代码必须最终可读”的完整声明,所有变量都应命名为 AZ,后跟 az(或其他一些任意构造,例如名词)。因为一些不熟练的人可能会将他们的变量命名为“SomethingUsefulButNotAllowedByTheCompilerBecauseSomeUsersMayDoDumbThings”。

Anyone who agrees with the idea that macros are bad should read the book, "With Folded Hands." http://en.wikipedia.org/wiki/With_Folded_Hands It tells a story about how we can keep people from doing stupid things all the way to the point of preventing them from doing very wise things.

While I like C#, I do really hate that it contributes to the stupidification of actual software engineers. So, yes, leave macros to the professionals. While we're at it, leave the naming of variables to professionals, too. That can make for some really unreadable code. To follow the full statement of "code must be ultimately readable" all variables should be named A-Z, followed by a-z (or some other arbitrary construct like only nouns). Because some unskilled person may name their variable "SomethingUsefulButNotAllowedByTheCompilerBecauseSomeUsersMayDoDumbThings".

贱贱哒 2024-08-10 14:40:57

您可以使用诸如 PropertyChanged 之类的宏来执行一些操作,例如 this

如果这比宏更好?
这是你必须决定的问题:)

You can do some thing you do with macros like PropertyChanged with ways like this

If thats better than macros ?
Thats a question YOU must decide :)

浅唱々樱花落 2024-08-10 14:40:56

来自 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 = 乘积 (1 + 2, 3 + 4, 5 + 6)

我希望得到的结果是3 * 7 *11 = 231,但事实上,我定义的扩展给出了:

int y = 1 + 2 * 3 + 4 * 5 + 6;

这给了我 33。我可以通过明智地应用括号来解决这个问题,但是编写一个在某些情况下有效但在其他情况下无效的宏非常容易。

尽管严格来说,C# 没有预处理器,但它确实具有可用于影响编译的条件编译符号。这些可以在代码中定义或使用编译器的参数来定义。 C# 中的“预处理”指令(命名只是为了与 C/C++ 保持一致,尽管没有单独的预处理步骤)是(摘自 ECMA 规范的文本):

#define 和 #undef
用于定义和取消定义条件编译符号

#if、#elif、#else 和 #endif

用于有条件地跳过源代码部分

#line
用于控制发出错误和警告的行号。

#error 和 #warning
用于发出错误和警告。

#region 和 #endregion

用于显式标记源代码部分。

有关上述内容的更多信息,请参阅 ECMA 规范第 9.5 节。还可以使用方法上的 Conditional 属性来实现条件编译,以便仅在定义了适当的符号时才编译对方法的调用。有关详细信息,请参阅 ECMA 规范的第 24.4.2 节。

作者:埃里克·冈纳森

from the C# faq.

http://blogs.msdn.com/CSharpFAQ/archive/2004/03/09/86979.aspx

Why doesn't C# support #define macros?
In C++, I can define a macro such as:

#define PRODUCT(x, y, z) x * y * z

and then use it in code:

int a = PRODUCT(3, 2, 1);

C# doesn't allow you to do this. Why?

There are a few reasons why. The first is one of readability.

One of our main design goals for C# is to keep the code very readable. Having the ability to write macros gives the programmer the ability to create their own language - one that doesn't necessarily bear any relation to what the code underneath. To understand what the code does, the user must not only understand how the language works, but he must also understand all of the #define macros that are in effect at that point in time. That makes code much harder to read.

In C#, you can use methods instead of macros, and in most cases, the JIT will inline them, giving you the same performance aspect.

There's also a somewhat more subtle issue. Macros are done textually, which means if I write:

int y = PRODUCT (1 + 2, 3 + 4, 5 + 6)

I would expect to get something that gives me 3 * 7 *11 = 231, but in fact, the expansion as I've defined it gives:

int y = 1 + 2 * 3 + 4 * 5 + 6;

which gives me 33. I can get around that by a judicious application of parenthesis, but its very easy to write a macro that works in some situations and not in others.

Although C# doesn't strictly speaking have a pre-processor, it does have conditional compilation symbols which can be used to affect compilation. These can be defined within code or with parameters to the compiler. The "pre-processing" directives in C# (named solely for consistency with C/C++, despite there being no separate pre-processing step) are (text taken from the ECMA specification):

#define and #undef
Used to define and undefine conditional compilation symbols

#if, #elif, #else and #endif

Used to conditionally skip sections of source code

#line
Used to control line numbers emitted for errors and warnings.

#error and #warning
Used to issue errors and warnings.

#region and #endregion

Used to explicitly mark sections of source code.

See section 9.5 of the ECMA specification for more information on the above. Conditional compilation can also be achieved using the Conditional attribute on a method, so that calls to the method will only be compiled when the appropriate symbol is defined. See section 24.4.2 of the ECMA specifcation for more information on this.

Author: Eric Gunnerson

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文