为什么默认不使用 C# "using aliases"?
Why C# "using aliases" are not used by default?
考虑以下代码。
using System.ComponentModel.DataAnnotations;
namespace Foo
{
public class Bar
{
[Required, MaxLength(250)]
public virtual string Name { get; set; }
}
}
除非你有一个奇特的 IDE(即在幕后进行各种查找和静态分析),否则 "Required" 和 "MaxLength" 的实际来源是相当模糊的。特别是当可能导入多个命名空间时,具有相似的含义。
作为 C# 的新手,我发现自己总是很难弄清楚某些东西的来源。尤其是在 Whosebug 等地方查看其他代码片段时。
using DataAnnotations = System.ComponentModel.DataAnnotations;
namespace Foo
{
public class Bar
{
[DataAnnotations.Required, DataAnnotations.MaxLength(250)]
public virtual string Name { get; set; }
}
}
现在很明显 "Required" 和 "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# 开发人员都认为别名的不良做法?可能有一些潜在的性能原因吗?
为什么 types/definitions 来自哪里很重要?
如果您真的很关心某个类型存在于哪个命名空间中,Visual Studio 可以通过 几种 方式找到答案,这两种方式是我最喜欢的如下:
- 将鼠标悬停在类型/声明上。 这通常会显示完整的类型名称。 (将鼠标悬停在
new SomeType()
语句上会显示方法名称,这是应用于属性的名称。)
- 按 F12/转到定义。 即使您没有定义的来源,也可以使用 F12 或 右键单击 -> 转到定义 将带您到显示该类型的所有 public 成员的元数据文件。这不适用于关键字(
out
、ref
、return
、null
等),但它适用于基本别名类型(int
、string
,等等)和传统类型(enum
,interface
,class
,struct
,等等)。这包括名称空间、类型名称和所有 public API 成员。如果有 XML 文档,它们也包括在内。如果您 F12 一个扩展方法,它会将您带到 class 元数据 该扩展方法 。这是非常有助于识别方法的来源,如果你觉得它是由不应该的东西注入的。
所以现在 真的 并不难确定该类型来自哪个命名空间。那么 using
别名呢,我们什么时候 真正 需要它们?
现实生活场景:我一直在为 XNA Framework 开发 Windows Forms 模型。 XNA Framework 有一个 Color
类型,而我的框架有一个 Color
类型。现在我经常同时使用这两个命名空间,但只需要 Color
类型中的一个 本机使用。很多时候我有一个 using
语句列表,其中包括如下内容:
using XnaColor = Microsoft.Xna.Framework.Color;
using Color = Evbpc.Framework.Drawing.Color;
所以这解决了一个歧义问题。
为什么 using
别名不是默认值?
可能是因为它们几乎从 不需要。我们真的不需要它们。如果您担心类型来自哪个命名空间,那么 far 进行快速查找比给所有内容加上别名和 force 命名空间更容易被定义为。按照这个速度,您也可以完全禁止 using
语句并完全限定所有内容。
我 曾经 遇到过的 using
别名的最大两个用例是:
- 解决类型之间的歧义。参见上面的示例。
解决命名空间之间的歧义。同上的想法,但是如果很多类型重复,我给整个命名空间起别名。
using XnaF = Microsoft.Xna.Framework;
using Evbpc.Framework.Drawing;
如果您使用 Visual Studio 生成代码、导入类型等,不会 使用别名。 Visual Studio 将根据需要完全限定名称。是否曾经右键单击波浪线并获得 A.B.Type
作为唯一选项而不是 using A.B
? 嗯,这通常是别名的好地方。
不过我要警告你,using
别名似乎增加了可维护性要求。 (这可能没有备份数字,但我不会说谎 - 我在这个项目中有几个别名导致我忘记了 how/what 我经常给别名命名 。)
一般来说,根据我的经验,如果您必须使用 using
别名,那么您 可能 违反了某处规则。
为什么我们甚至 不定期使用它们?
因为他们很烂。它们使代码更难阅读(以 DataAnnotations.MaxLength
为例,我为什么需要阅读它?我不关心 MaxLength
在 System.ComponentModel.DataAnnotations
中,我只关心它的设置正确地),它们使代码混乱(现在我被迫记住一个属性在System.ComponentModel.DataAnnotations
而不是System.ComponentModel.DataAnnotations.Schema
),而且它们通常很笨重。
以你之前的例子为例,我有一个 Entity Framework 项目,它在 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; }
现在用你的例子我会得到以下之一:
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; }
对不起,那些太糟糕了。这就是为什么 'every' 与您交谈的开发人员会避开它们并认为这是个坏主意。我将坚持智能地[1]导入名称空间并处理非常分钟的潜力类型冲突。 那我就用个别名吧
如果您真的找不到类型所在的名称空间(假设您从 Stack Overflow 中提取代码),则点击 MSDN, go to the Library 并搜索该类型。 (即,搜索 KeyAttribute
或 MaxLengthAttribute
,第一个链接是 API 参考。)
[1]:聪明地我的意思是带着责任和谨慎去做。不要只是 盲目地 导入/使用名称空间,尽量限制它们。 SRP 和多态性通常允许我们在每个文件中保持 using
列表非常小。
考虑以下代码。
using System.ComponentModel.DataAnnotations;
namespace Foo
{
public class Bar
{
[Required, MaxLength(250)]
public virtual string Name { get; set; }
}
}
除非你有一个奇特的 IDE(即在幕后进行各种查找和静态分析),否则 "Required" 和 "MaxLength" 的实际来源是相当模糊的。特别是当可能导入多个命名空间时,具有相似的含义。
作为 C# 的新手,我发现自己总是很难弄清楚某些东西的来源。尤其是在 Whosebug 等地方查看其他代码片段时。
using DataAnnotations = System.ComponentModel.DataAnnotations;
namespace Foo
{
public class Bar
{
[DataAnnotations.Required, DataAnnotations.MaxLength(250)]
public virtual string Name { get; set; }
}
}
现在很明显 "Required" 和 "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# 开发人员都认为别名的不良做法?可能有一些潜在的性能原因吗?
为什么 types/definitions 来自哪里很重要?
如果您真的很关心某个类型存在于哪个命名空间中,Visual Studio 可以通过 几种 方式找到答案,这两种方式是我最喜欢的如下:
- 将鼠标悬停在类型/声明上。 这通常会显示完整的类型名称。 (将鼠标悬停在
new SomeType()
语句上会显示方法名称,这是应用于属性的名称。) - 按 F12/转到定义。 即使您没有定义的来源,也可以使用 F12 或 右键单击 -> 转到定义 将带您到显示该类型的所有 public 成员的元数据文件。这不适用于关键字(
out
、ref
、return
、null
等),但它适用于基本别名类型(int
、string
,等等)和传统类型(enum
,interface
,class
,struct
,等等)。这包括名称空间、类型名称和所有 public API 成员。如果有 XML 文档,它们也包括在内。如果您 F12 一个扩展方法,它会将您带到 class 元数据 该扩展方法 。这是非常有助于识别方法的来源,如果你觉得它是由不应该的东西注入的。
所以现在 真的 并不难确定该类型来自哪个命名空间。那么 using
别名呢,我们什么时候 真正 需要它们?
现实生活场景:我一直在为 XNA Framework 开发 Windows Forms 模型。 XNA Framework 有一个 Color
类型,而我的框架有一个 Color
类型。现在我经常同时使用这两个命名空间,但只需要 Color
类型中的一个 本机使用。很多时候我有一个 using
语句列表,其中包括如下内容:
using XnaColor = Microsoft.Xna.Framework.Color;
using Color = Evbpc.Framework.Drawing.Color;
所以这解决了一个歧义问题。
为什么 using
别名不是默认值?
可能是因为它们几乎从 不需要。我们真的不需要它们。如果您担心类型来自哪个命名空间,那么 far 进行快速查找比给所有内容加上别名和 force 命名空间更容易被定义为。按照这个速度,您也可以完全禁止 using
语句并完全限定所有内容。
我 曾经 遇到过的 using
别名的最大两个用例是:
- 解决类型之间的歧义。参见上面的示例。
解决命名空间之间的歧义。同上的想法,但是如果很多类型重复,我给整个命名空间起别名。
using XnaF = Microsoft.Xna.Framework; using Evbpc.Framework.Drawing;
如果您使用 Visual Studio 生成代码、导入类型等,不会 使用别名。 Visual Studio 将根据需要完全限定名称。是否曾经右键单击波浪线并获得 A.B.Type
作为唯一选项而不是 using A.B
? 嗯,这通常是别名的好地方。
不过我要警告你,using
别名似乎增加了可维护性要求。 (这可能没有备份数字,但我不会说谎 - 我在这个项目中有几个别名导致我忘记了 how/what 我经常给别名命名 。)
一般来说,根据我的经验,如果您必须使用 using
别名,那么您 可能 违反了某处规则。
为什么我们甚至 不定期使用它们?
因为他们很烂。它们使代码更难阅读(以 DataAnnotations.MaxLength
为例,我为什么需要阅读它?我不关心 MaxLength
在 System.ComponentModel.DataAnnotations
中,我只关心它的设置正确地),它们使代码混乱(现在我被迫记住一个属性在System.ComponentModel.DataAnnotations
而不是System.ComponentModel.DataAnnotations.Schema
),而且它们通常很笨重。
以你之前的例子为例,我有一个 Entity Framework 项目,它在 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; }
现在用你的例子我会得到以下之一:
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; }
对不起,那些太糟糕了。这就是为什么 'every' 与您交谈的开发人员会避开它们并认为这是个坏主意。我将坚持智能地[1]导入名称空间并处理非常分钟的潜力类型冲突。 那我就用个别名吧
如果您真的找不到类型所在的名称空间(假设您从 Stack Overflow 中提取代码),则点击 MSDN, go to the Library 并搜索该类型。 (即,搜索 KeyAttribute
或 MaxLengthAttribute
,第一个链接是 API 参考。)
[1]:聪明地我的意思是带着责任和谨慎去做。不要只是 盲目地 导入/使用名称空间,尽量限制它们。 SRP 和多态性通常允许我们在每个文件中保持 using
列表非常小。