为什么默认情况下不使用C#"使用别名"?

Bra*_*rad 6 .net c# ide visual-studio

请考虑以下代码.

using System.ComponentModel.DataAnnotations;

namespace Foo
{
    public class Bar
    {
        [Required, MaxLength(250)]
        public virtual string Name { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

除非你有一个花哨的IDE(在幕后进行各种查找和静态分析),否则"必需"和"MaxLength"实际来自哪里都很模糊.特别是当可能导入多个名称空间时,具有相似的含义.

作为C#的相对新手,我发现自己总是很难弄清楚某些事情的来源.特别是在查看StackOverflow等地方的其他代码片段时.

using DataAnnotations = System.ComponentModel.DataAnnotations;

namespace Foo
{
    public class Bar
    {
        [DataAnnotations.Required, DataAnnotations.MaxLength(250)]
        public virtual string Name { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在很明显"必需"和"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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

这与PHP和Js ES6的工作方式非常相似.

我很好奇为什么这不是C#的默认值?为什么我和其他所有C#开发人员一起考虑别名的不良做法?是否存在一些潜在的性能原因?

410*_*one 7

为什么类型/定义来自何处?

如果您真正担心类型所在的命名空间,Visual Studio能够以多种方式查找,我最喜欢的两个是:

  • 悬停类型/声明.这通常会显示完整的类型名称.(悬停new SomeType()语句会显示方法名称,即应用于属性的方法名称.)
  • 按F12 /转到定义.即使您没有定义的来源,使用F12Right Click- > Go To Definition也会转到显示该类型的所有公共成员的元数据文件.这不会对关键字(out,ref,return,null,等),但它的工作原理基本别名类型(int,string,等)和传统的类型(enum,interface,class,struct,等).这包括命名空间,类型名称和所有公共API成员.如果有XML文档,也包含它们.如果您F12使用扩展方法,则会转到该扩展方法的类元数据.这是非常识别有用的,其中一个方法,从如果你觉得它是由它的东西注入进来不应该已.

所以,现在这不是真的那么困难的决定是什么名称空间的类型是从哪里来的.那么using别名呢,我们什么时候才真正需要它们呢?

真实场景:我一直在为XNA Framework开发Windows窗体模型.XNA Framework有一个Color类型,我的框架有一个Color类型.现在,我经常用这两个命名空间在一起,但只需要一个对的Color类型进行本机使用.通常我会有一个using包含以下内容的语句列表:

using XnaColor = Microsoft.Xna.Framework.Color;
using Color = Evbpc.Framework.Drawing.Color;
Run Code Online (Sandbox Code Playgroud)

所以这解决了一个含糊不清的问题.

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

可能是因为他们几乎没有必要.我们真的不需要它们.如果你很在意一类来自哪个命名空间从它的容易做到快速查找比它别名一切,迫使一个命名空间中定义.按照这个速度,你可以using完全禁止陈述并完全限定一切.

我最大的两个用,例曾经有一个using别名有:

  1. 解决类型之间的歧义.见上面的例子.
  2. 解决名称空间之间的歧义.与上面的想法相同,但如果复制了很多类型,我就会使用整个命名空间.

    using XnaF = Microsoft.Xna.Framework;
    using Evbpc.Framework.Drawing;
    
    Run Code Online (Sandbox Code Playgroud)

如果您使用Visual Studio生成代码,导入类型等,则不会使用别名.相反,Visual Studio将根据需要对名称进行完全限定.有没有右键单击一个波浪线A.B.Type而是作为唯一的选择而不是using A.B那通常是别名的好地方.

我会警告你,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; }
Run Code Online (Sandbox Code Playgroud)

现在用你的例子,我将有以下之一:

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; }
Run Code Online (Sandbox Code Playgroud)

要么:

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; }
Run Code Online (Sandbox Code Playgroud)

或者更糟糕的是:

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; }
Run Code Online (Sandbox Code Playgroud)

对不起,但那些都很可怕.这就是为什么你说话的'每个'开发者都会避开它们并认为这是一个坏主意.我将坚持智能地[1]导入名称空间并处理类型冲突的非常微小的潜力.然后我会使用别名.

如果你真的找不到类型所在的命名空间(比如你从Stack Overflow中提取代码),那么点击MSDN,转到并搜索类型.(即,搜索KeyAttribute或者MaxLengthAttribute第一个链接是API引用.)

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