使用带有泛型的using语句:使用ISet<> = System.Collections.Generic.ISet<>

52

因为我使用了两个不同的泛型集合名称空间(System.Collections.GenericIesi.Collections.Generic),所以发生冲突。在项目的其他部分,我同时使用nunit和mstest框架,但是当我调用Assert时,我想要使用nunit版本。

using Assert = NUnit.Framework.Assert;

这很好用,但我想使用通用类型来做同样的事情。但是,以下几行不起作用:

using ISet = System.Collections.Generic.ISet;
using ISet<> = System.Collections.Generic.ISet<>;

有人知道如何告诉 .NET 如何使用泛型类的 using 语句吗?


6
这是一个偶尔被要求的功能。它已经在可能的功能清单上很长时间了,但从未优先级高到实际实现的程度。 - Eric Lippert
Eric,这是我第一次遇到这个问题,因为.NET 4.0框架添加了ISet<>,而Iesi.Collections dll则针对3.5。通常其他开发人员都很好地避免与标准的.NET命名冲突。 - Jason More
2
为什么你把它放在两个不同的命名空间中?你能提供更多信息吗? - David L
我会用不同的措辞表达。有意地为两个不同的事物使用相同的名称将会很不方便。只有在极不可能同时“使用”这两个命名空间时,这种方法才最有效。 - Roman Starkov
@EricLippert 当将代码从Java或Haskell等支持精确符号导入的语言转换到C#时(例如在Java中使用import myModule.MyClass;),我发现这是C#的一个主要缺陷,因为你必须从System.Collections.Generic中使用所有东西,即使你只需要IEnumerable<>用于你的LINQ表达式。Java不允许重命名,但我认为导入重命名实际上只是“偶尔”被要求的,而不是精确的导入/使用。 - Earth Engine
6个回答

52

遗憾的是,using指令并不能达到你想要的效果。你可以这样写:

using Frob = System.String;

using ListOfInts = System.Collections.Generic.List<System.Int32>;

但是您不能说

using Blob<T> = System.Collections.Generic.List<T>
或者
using Blob = System.Collections.Generic.List

这是语言的一个短板,从未得到纠正。


2
如何最好地游说引入这个功能? - miniBill
@miniBill:尝试在Roslyn.codeplex.com的语言设计论坛上发布。 - Eric Lippert
3
这里有一个提案(链接:https://github.com/dotnet/csharplang/issues/1239)。我也很希望拥有这个功能。 - theStrawMan

45

我认为你最好别将通用类型别名化,而是将命名空间本身进行别名化(这似乎不可能)。

因此,例如:

using S = System.Collections.Generic;
using I = Iesi.Collections.Generic;

举个例子,对于一个BCL中的ISet<int>

S.ISet<int> integers = new S.HashSet<int>();

非常好的建议!我刚遇到了完全相同的问题,但这个解决方法并没有立即想到我。 - julealgon
1
只有当命名空间是长的部分时,这才有效。如果类型参数本身具有冗长的类型名称,则你就没那么幸运了。 - Drew Noakes
刚遇到了同样的问题。我想在构造函数中使用泛型类中定义的常量作为默认参数值,而且有4个,所以我必须输入完整的冗长类名,包括它的泛型参数和常量名。如果语言允许在泛型类内部使用using语句,比如using C = Long.Name<TKey,TValue>,这个问题就可以解决了。在类外部,泛型参数是未知的,所以没有用处。 - Triynko

7
唯一的方法是将泛型类型特化,如下所示进行别名。
using IntSet = System.Collections.Generic.ISet<int>;

您在示例中所做的那样,无法将开放泛型类型用作别名:
using MySet = System.Collections.Generic.ISet<>;

谢谢Steve,我以后会用得上这个! - Jason More
你的第一个示例为什么在VS2017上无法编译? - mr5

3

你的别名和类名本身相同,因此你仍然存在歧义,就像你对每个命名空间都使用了using一样。 给类的别名一个不同的名称,例如:

using FirstNamespace;
using OtherObject = SecondNamespace.MyObject;

public class Foo
{
    public void Bar()
    {
        MyObject first = new MyObject;//will be the MyObject from the first namespace
        OtherObject second = new OtherObject;
    }
}

1
在某些情况下,您可以使用继承:

public class MyList<T1, T2> : List<Tuple<IEnumerable<HashSet<T1>>, IComparable<T2>>> { }

public void Meth()
{
    var x = new MyList<int, bool>();
}

0
你可以使用以下方式给一个类起别名:
using Test = NameSpace.MyClass;

仅当类不是泛型时。


4
可以对泛型类进行别名,只需要在别名中指定一个具体类型,而不是保持它的泛型形式。 - Servy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接