人们会在何时何地使用命名空间别名,例如
using someOtherName = System.Timers.Timer;
在我看来,这只会给理解语言带来更多混乱。
那是类型别名,而不是命名空间别名;消除歧义很有用 - 例如,反对:
using WinformTimer = System.Windows.Forms.Timer;
using ThreadingTimer = System.Threading.Timer;
(ps:感谢您的选择
Timer
;-p)
否则,如果您在同一个文件中同时使用
System.Windows.Forms.Timer
和 System.Threading.Timer
,那么您必须继续提供全名(因为 Timer
可能会造成混淆)。
它还与
extern
别名一起使用,用于使用来自不同程序集的具有相同完全限定类型名称的类型 - 很少见,但支持它很有用。
实际上,我可以看到另一种用途:当您想要快速访问类型但不想使用常规
using
,因为您无法导入一些冲突的扩展方法时。有点复杂,但这是一个例子:
namespace RealCode {
//using Foo; // can't use this - it breaks DoSomething
using Handy = Foo.Handy;
using Bar;
static class Program {
static void Main() {
Handy h = new Handy(); // prove available
string test = "abc";
test.DoSomething(); // prove available
}
}
}
namespace Foo {
static class TypeOne {
public static void DoSomething(this string value) { }
}
class Handy {}
}
namespace Bar {
static class TypeTwo {
public static void DoSomething(this string value) { }
}
}
当我有多个具有冲突的子命名空间和/或对象名称的命名空间时,我会使用它,你可以执行类似[作为示例]的操作:
using src = Namespace1.Subspace.DataAccessObjects;
using dst = Namespace2.Subspace.DataAccessObjects;
...
src.DataObject source = new src.DataObject();
dst.DataObject destination = new dst.DataObject();
否则必须写成:
Namespace1.Subspace.DataAccessObjects.DataObject source =
new Namespace1.Subspace.DataAccessObjects.DataObject();
Namespace2.Subspace.DataAccessObjects.DataObject dstination =
new Namespace2.Subspace.DataAccessObjects.DataObject();
它可以节省大量的打字时间,并且可以使代码更易于阅读。
除了提到的示例之外,在重复引用泛型类型时,类型别名(而不是命名空间别名)也很方便:
Dictionary<string, SomeClassWithALongName> foo = new Dictionary<string, SomeClassWithALongName>();
private void DoStuff(Dictionary<string, SomeClassWithALongName> dict) {}
对比:
using FooDict = Dictionary<string, SomeClassWithALongName>;
FooDict foo = new FooDict();
private void DoStuff(FooDict dict) {}
简洁。
在共享类型名称的命名空间之间提供清晰度有一些附带好处,但本质上它只是糖。
我总是在这种情况下使用它
using Utility = MyBaseNamespace.MySubNamsepace.Utility;
其中
Utility
否则会有不同的上下文(如 MyBaseNamespace.MySubNamespace.MySubSubNamespace.Utility
),但我希望/更喜欢 Utility
始终指向该特定类别。
当您在多个包含的命名空间中有多个具有相同名称的类时,它非常有用。 例如...
namespace Something.From.SomeCompanyA {
public class Foo {
/* ... */
}
}
namespace CompanyB.Makes.ThisOne {
public class Foo {
/* ... */
}
}
您可以使用别名来让编译器满意,并使您和团队中的其他人更清楚地了解事情:
using CompanyA = Something.From.CompanyA;
using CompanyB = CompanyB.Makes.ThisOne;
/* ... */
CompanyA.Foo f = new CompanyA.Foo();
CompanyB.Foo x = new CompanyB.Foo();
我们为所有命名空间定义了命名空间别名。这使得很容易看出一个类来自哪里,例如:
using System.Web.WebControls;
// lots of other using statements
// contains the domain model for project X
using dom = Company.ProjectX.DomainModel;
// contains common web functionality
using web = Company.Web;
// etc.
和
// User from the domain model
dom.User user = new dom.User();
// Data transfer object
dto.User user = new dto.User();
// a global helper class
utl.SomeHelper.StaticMethod();
// a hyperlink with custom functionality
// (as opposed to System.Web.Controls.HyperLink)
web.HyperLink link = new web.HyperLink();
我们已经定义了一些别名必须如何命名的准则,并且每个人都在使用它们。
我发现别名在单元测试中非常有用。当您编写单元测试时,通常的做法是将测试主题声明为
MyClass myClassUT;
成为
myClassUT
主题 Under Test。但是,如果您想为具有静态方法的静态类编写单元测试怎么办?然后你可以创建一个像这样的别名:
using MyStaticClassUT = Namespace.MyStaticClass;
然后你可以像这样编写单元测试:
public void Test()
{
var actual = MyStaticClassUT.Method();
var expected = ...
}
并且您永远不会忘记被测试的主题是什么。
从某种意义上说,在 Visual Studio 中编码时它确实非常方便。
用例:假设我只需要使用几个类,例如
SqlConnection
来自命名空间 System.Data
。通常情况下,我将导入 *.cs 文件顶部的 System.Data.SqlClient
命名空间,如下所示:
using System.Data;
现在看看我的智能感知。在代码编辑器中输入时,它的数量急剧增加,有大量的类可供选择。我根本不会使用一大堆课程:
所以我宁愿在 *.cs 文件顶部使用别名并获得清晰的智能感知视图:
using SqlDataCon = System.Data.SqlClient.SqlConnection
现在看看我的智能感知视图。超级清晰超级干净。
我知道的一个原因;当导入的命名空间发生名称冲突时,它允许您使用较短的名称。 示例:
如果您在访问
using System.Windows.Forms;
时在同一个文件中声明了 using System.Windows.Input;
和 ModifierKeys
,您可能会发现名称 ModifierKeys
位于 System.Windows.Forms.Control
和 System.Windows.Input
命名空间中。
因此,通过声明 using Input = System.Windows.Input;
,您可以通过 System.Windows.Input.ModifierKeys
获得 Input.ModifierKeys
。
我不是 C# 爱好者,但别名命名空间对我来说似乎是“最佳实践”。这样您就知道自己得到了什么,并且仍然不必输入太多内容。
您可以使用它们非常轻松地修改代码。
例如:
#if USE_DOUBLES
using BNumber = System.Double;
#else
using BNumber = System.Single;
#endif
public void BNumber DoStuff(BNumber n) {
// ...
}
public void BNumber DoStuff2(BNumber n) {
// ...
}
public void BNumber DoStuff3(BNumber n) {
// ...
}
通过简单更改指令,您可以决定整个代码是否适用于
float
或 double
。
已经提到过,但另一个非常有用的例子是避免非常长而混乱的类名。
这可以改变这个:
int bySortWeight(KeyValuePair<Recipe, ItemDrop.ItemData> a, KeyValuePair<Recipe, ItemDrop.ItemData> b) => a.Key.m_listSortWeight.CompareTo(b.Key.m_listSortWeight);
int byName(KeyValuePair<Recipe, ItemDrop.ItemData> a, KeyValuePair<Recipe, ItemDrop.ItemData> b) => a.Key.m_item.m_itemData.m_shared.m_name.CompareTo(b.Key.m_item.m_itemData.m_shared.m_name);
变得更加清洁:
using KVP = System.Collections.Generic.KeyValuePair<Recipe, ItemDrop.ItemData>;
int bySortWeight(KVP a, KVP b) => a.Key.m_listSortWeight.CompareTo(b.Key.m_listSortWeight);
int byName(KVP a, KVP b) => a.Key.m_item.m_itemData.m_shared.m_name.CompareTo(b.Key.m_item.m_itemData.m_shared.m_name);
Piktiv 和朋友共进晚餐