为什么C#“使用别名”默认不使用?(Why C# “using aliases” are not used by default? [closed])

编程入门 行业动态 更新时间:2024-10-28 13:14:22
为什么C#“使用别名”默认不使用?(Why C# “using aliases” are not used by default? [closed])

考虑下面的代码。

using System.ComponentModel.DataAnnotations; namespace Foo { public class Bar { [Required, MaxLength(250)] public virtual string Name { get; set; } } }

除非你有一个漂亮的IDE(这是在幕后进行各种查找和静态分析),对于“Required”和“MaxLength”实际来自哪里,它是非常模糊的。 特别是当可能导入几个名称空间时,具有相似的含义。

作为C#的相对新手,我发现自己总是很难找出某些事情来自哪里。 特别是在查看StackOverflow等其他代码片段时。

using DataAnnotations = System.ComponentModel.DataAnnotations; namespace Foo { public class Bar { [DataAnnotations.Required, DataAnnotations.MaxLength(250)] public virtual string Name { get; set; } } }

现在很明显,“必需”和“MaxLength”来自哪里。 你可以采取另一步,做一些事情:

using Required = System.ComponentModel.DataAnnotations.RequiredAttribute; using MaxLength = System.ComponentModel.DataAnnotations.MaxLengthAttribute; namespace Foo { public class Bar { [Required, MaxLength(250)] public virtual string Name { get; set; } } }

现在这与PHP和Js ES6的工作方式非常相似。

我很好奇为什么这不是C#的默认值? 为什么几乎所有其他的C#开发者都认为别名是坏习惯? 也许有一些潜在的性能原因吗?

Consider the following code.

using System.ComponentModel.DataAnnotations; namespace Foo { public class Bar { [Required, MaxLength(250)] public virtual string Name { get; set; } } }

Unless you have a fancy IDE (that is doing all sorts lookups & static analysis behind the scenes) it's pretty ambiguous as to where "Required" & "MaxLength" actually come from. Especially when several namespaces might be imported, with similar meaning.

As a relative newbie to C# I am finding myself always having a hard time figuring out where certain things come from. Especially when looking at other code snippets on places like StackOverflow.

using DataAnnotations = System.ComponentModel.DataAnnotations; namespace Foo { public class Bar { [DataAnnotations.Required, DataAnnotations.MaxLength(250)] public virtual string Name { get; set; } } }

Now it's very obvious where "Required" & "MaxLength" come from. You could take it another step and do something like:

using Required = System.ComponentModel.DataAnnotations.RequiredAttribute; using MaxLength = System.ComponentModel.DataAnnotations.MaxLengthAttribute; namespace Foo { public class Bar { [Required, MaxLength(250)] public virtual string Name { get; set; } } }

This is now very similar to how both PHP & Js ES6 works.

I'm curious as to why this isn't the default for C#? And why pretty much every other C# dev I have spoken with considers alias's bad practice? Is there some underlying performance reason perhaps?

最满意答案

为什么类型/定义来自哪里?

如果您真的关心某种类型的命名空间,Visual Studio有能力以多种方式查找,下面是我最喜欢的两个:

悬停类型/声明。 这通常会向您显示完整的类型名称。 (悬停一个new SomeType()语句向您显示方法名,这是应用于属性的方法名。) 按F12 /转到定义。 即使您没有定义的来源,使用F12右键单击 - > 去定义将带您到元数据文件,该文件向您显示该类型的所有公共成员。 这对关键字( out , ref , return , null等)不起作用,但它适用于基本的别名类型( int , string等)和传统类型( enum , interface , class , struct等)。 这包括名称空间,类型名称和所有公共API成员。 如果有XML文档,它们也包含在内。 如果您使用F12扩展方法,则会将您引导至该扩展方法的类元数据。 如果你觉得它是由本来不应该注入的东西注入的,那么这对于识别方法来自何处非常有用。

所以现在确定类型来自哪个名称空间并不是那么困难。 那么using别名怎么样,我们什么时候需要它们呢?

真实生活场景:我一直在为XNA框架开发Windows Forms模型。 XNA框架有一个Color类型,我的框架有一个Color类型。 现在我经常同时使用这两个名称空间,但只需要其中一种 Color类型在本地使用。 通常情况下,我有一个using语句的列表,其中包含如下内容:

using XnaColor = Microsoft.Xna.Framework.Color; using Color = Evbpc.Framework.Drawing.Color;

所以这解决了一个模棱两可的问题。

为什么不using别名作为默认值?

可能因为他们几乎没有必要。 我们并不需要它们。 如果您担心某个类型的名称空间来自哪个名称空间,那么执行快速查找要比将所有内容别名并强制定义名称空间要容易得多。 以这样的速度,你可能会尽可能地using语句并完全限定所有内容。

我使用的最大的两个用例是:

解决类型之间的歧义。 见上面的例子。

解决名称空间之间的歧义。 如上所述,但如果许多类型都被复制,我会将其命名为整个命名空间。

using XnaF = Microsoft.Xna.Framework; using Evbpc.Framework.Drawing;

如果您使用Visual Studio生成代码,导入类型等,则不会使用别名。 相反,Visual Studio将根据需要完全限定名称。 用鼠标右键单击一个ABType ,并将ABType作为唯一选项而不是using AB ? 那通常是一个别名的好地方。

不过,我会警告你, using别名似乎会增加可维护性要求。 (这可能没有数字备份,但我不会说谎 - 这个项目我有几个别名,导致我忘记了我经常如何/命名别名。)

一般来说,根据我的经验,如果你必须using别名,你可能会在某个地方违规。

为什么我们不能定期使用它们?

因为他们吸吮。 他们使代码难以阅读(以DataAnnotations.MaxLength为例,为什么我需要阅读该代码?我不关心MaxLength在System.ComponentModel.DataAnnotations ,我只关心它的设置是否正确),它们会混淆代码(现在我不得不记住一个属性在System.ComponentModel.DataAnnotations而不是System.ComponentModel.DataAnnotations.Schema ),并且它们通常很笨重。

拿你之前的例子来说,我有一个实体框架项目,它在类中具有类似以下的属性:

using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; [Key, Column(Order = 2)] [MaxLength(128)] public string UserId { get; set; } [ForeignKey(nameof(UserId))] public virtual ApplicationUser User { get; set; }

现在用你的例子,我会有以下其中一个:

using DataAnnotations = System.ComponentModel.DataAnnotations; [DataAnnotations.Key, DataAnnotations.Schema.Column(Order = 2)] [DataAnnotations.MaxLength(128)] public string UserId { get; set; } [DataAnnotations.Schema.ForeignKey(nameof(UserId))] public virtual ApplicationUser User { get; set; }

要么:

using DataAnnotations = System.ComponentModel.DataAnnotations; using Schema = System.ComponentModel.DataAnnotations.Schema; [DataAnnotations.Key, Schema.Column(Order = 2)] [DataAnnotations.MaxLength(128)] public string UserId { get; set; } [Schema.ForeignKey(nameof(UserId))] public virtual ApplicationUser User { get; set; }

或者更糟的是:

using KeyAttribute = System.ComponentModel.DataAnnotations.KeyAttribute; using MaxLengthAttribute = System.ComponentModel.DataAnnotations.MaxLengthAttribute; using ColumnAttribute = System.ComponentModel.DataAnnotations.Schema.ColumnAttribute; using ForeignKeyAttribute = System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute; [Key, Column(Order = 2)] [MaxLength(128)] public string UserId { get; set; } [ForeignKey(nameof(UserId))] public virtual ApplicationUser User { get; set; }

我很抱歉,但这些都很糟糕 。 这就是为什么你所说的每一个开发者都会避开它们,并认为这是一个糟糕的主意。 我会坚持聪明地 [1]导入命名空间并处理类型冲突的非常微小的潜力。 然后我会使用别名。

如果你真的无法找到某个类型所在的名称空间(比如说从Stack Overflow中提取代码),请打开MSDN ,进入Library并搜索类型。 (即,搜索KeyAttribute或MaxLengthAttribute并且第一个链接是API参考。)

[1]: 聪明地说,我的意思是在责任和关心的情况下这样做。 不要盲目地导入/使用名称空间,尽量限制它们。 SRP和多​​态性通常允许我们在每个文件中保持using列表非常小。

Why does it matter where types/definitions come from?

If you're truly that concerned about what namespace a type is present in, Visual Studio has the ability to find out in several ways, the two that are my favourite are below:

Hover the type / declaration. This often shows you the full type-name. (Hovering a new SomeType() statement shows you the method name, which is what is applied to attributes.) Press F12 / Go To Definition. Even if you don't have the source for the definition, using the F12 or Right Click -> Go To Definition will take you to the metadata file that shows you all the public members of the type. This doesn't work on keywords (out, ref, return, null, etc.) but it works on basic aliased types (int, string, etc.) and traditional types (enum, interface, class, struct, etc.). This includes the namespace, type-name, and all public API members. If there are XML docs they are included as well. If you F12 an extension-method it takes you to the class metadata for that extension method. This is extremely helpful for identifying where a method came from if you feel it was injected by something it shouldn't have been.

So now it's not really that difficult the determine what namespace that the type came from. So what about the using aliases, when do we actually need them?

Real life scenario: I have been working on a Windows Forms model for the XNA Framework. XNA Framework has a Color type, and my framework has a Color type. Now I often use both those namespaces together but only need one of the Color types to be used natively. Often times I have a list of using statements that include something like:

using XnaColor = Microsoft.Xna.Framework.Color; using Color = Evbpc.Framework.Drawing.Color;

So this resolves an ambiguity issue.

Why aren't using aliases a default?

Probably because they're almost never necessary. We don't really need them. If you're concerned about what namespace a type comes from it's far easier to do a quick lookup than it is to alias everything and force a namespace to be defined. At that rate you may-as-well bar using statements altogether and fully-qualify everything.

The biggest two use-cases I've ever had for a using alias are:

Resolve ambiguity between types. See example above.

Resolve ambiguity between namespaces. Same idea as above, but I alias a whole namespace if a lot of types are duplicated.

using XnaF = Microsoft.Xna.Framework; using Evbpc.Framework.Drawing;

If you're generating code with Visual Studio, importing types, etc., it's not going to use an alias. Visual Studio will, instead, fully-qualify the name as necessary. Ever right-click a squiggle and get A.B.Type as the only option instead of using A.B? Well that's usually a good spot for an alias.

I'll warn you though, using aliases seem to increase maintainability requirements. (This may not have numbers backed up, but I won't lie - this project that I have several aliases in causes me to forget how/what I named an alias frequently.)

Generally, in my experience, if you have to use a using alias, you are probably breaking a rule somewhere.

Why don't we even use them on a regular basis?

Because they suck. They make code harder to read (take your example of DataAnnotations.MaxLength, why do I need to read that? I don't care that MaxLength is in System.ComponentModel.DataAnnotations, I only care that it's set properly), they disorganize code (now I am forced to remember that an attribute is in System.ComponentModel.DataAnnotations instead of System.ComponentModel.DataAnnotations.Schema), and they are just generally clunky.

Take your previous example, I have an Entity Framework project which has attributes something like the following on a class:

using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; [Key, Column(Order = 2)] [MaxLength(128)] public string UserId { get; set; } [ForeignKey(nameof(UserId))] public virtual ApplicationUser User { get; set; }

Now with your example I would have one of the following:

using DataAnnotations = System.ComponentModel.DataAnnotations; [DataAnnotations.Key, DataAnnotations.Schema.Column(Order = 2)] [DataAnnotations.MaxLength(128)] public string UserId { get; set; } [DataAnnotations.Schema.ForeignKey(nameof(UserId))] public virtual ApplicationUser User { get; set; }

Or:

using DataAnnotations = System.ComponentModel.DataAnnotations; using Schema = System.ComponentModel.DataAnnotations.Schema; [DataAnnotations.Key, Schema.Column(Order = 2)] [DataAnnotations.MaxLength(128)] public string UserId { get; set; } [Schema.ForeignKey(nameof(UserId))] public virtual ApplicationUser User { get; set; }

Or worse yet:

using KeyAttribute = System.ComponentModel.DataAnnotations.KeyAttribute; using MaxLengthAttribute = System.ComponentModel.DataAnnotations.MaxLengthAttribute; using ColumnAttribute = System.ComponentModel.DataAnnotations.Schema.ColumnAttribute; using ForeignKeyAttribute = System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute; [Key, Column(Order = 2)] [MaxLength(128)] public string UserId { get; set; } [ForeignKey(nameof(UserId))] public virtual ApplicationUser User { get; set; }

I'm sorry, but those are just terrible. This is why 'every' dev you talk to avoids them and thinks this is a bad idea. I'll just stick to intelligently[1] importing namespaces and deal with the very minute potential that types clash. Then I'll use an alias.

If you really cannot find what namespace a type is in (say you pull code from Stack Overflow) then hit up MSDN, go to the Library and search for the type. (I.e., search for KeyAttribute or MaxLengthAttribute and the first links are the API references.)

[1]: By intelligently I mean doing so with responsibility and care. Don't just blindly import / use namespaces, try to limit them as much as possible. SRP and polymorphism usually allow us to keep the using list pretty small in each file.

更多推荐

本文发布于:2023-08-04 16:51:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1417923.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:别名   aliases   closed   default

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!