定义类型别名


74

我发现Pascal的一个功能非常有用,那就是能够命名数据类型,例如

type
 person: record
             name: string;
             age: int;
         end;

var
 me: person;
 you: person;

etc

您可以在C#中做类似的事情吗?我希望能够做类似的事情

using complexList = List<Tuple<int,string,int>>;

complexList peopleList;
anotherList otherList;

这样一来,如果我必须更改数据类型的定义,就可以在一个地方进行。

C#是否支持实现此目标的方法?


9
usingc#中的“别名”仅针对每个文件
Marc Gravell

下面是与此相关的另一个问题是:stackoverflow.com/questions/161477/...

Answers:


62

这并不是在Pascal中执行的操作,但是可以使用using-directive。在这里看看如何使用它

例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyList = Dummy2.CompleXList;

namespace Dummy2
{
    public class Person 
    {
    }

    public class CompleXList : List<Person> 
    { 
    }


    class Program
    {
        static void Main(string[] args)
        {
            MyList l1 = new MyList();
        }
    }
}

27
次要点:using文件顶部的是指令,而不是语句;“使用声明”是涉及的东西IDisposable。特别是,这是“使用别名”。
Marc Gravell

2
注意:同样,如果仅将类命名为“ MyList”,则当然不再需要using指令(这也解决了原始问题)。
BrainSlugs83

该链接指向旧的文档页面。虽然仍旧有效且准确(并且具有下面的链接),但是如果删除旧页面,则此处是指向新页面的链接。 docs.microsoft.com/en-us/dotnet/csharp/language-reference/…–
MadCityDev

2
这以某种方式对命名元组有效吗?我不能使它工作。我尝试的是:using MyType = (TypeA a, TypeB b);。我想我可以使用未命名元组和它的工作,但我真的想名字,而不是Item1Item2。:(
user2173353 '19

85

是的,有可能。你可以写:

using System;
using System.Collections.Generic;

namespace ConsoleApplication12
{
    using MyAlias = List<Tuple<int, string, int>>;
}

或者,如果在名称空间之外声明:

using System;
using System.Collections.Generic;

using MyAlias = System.Collections.Generic.List<System.Tuple<int, string, int>>;

namespace ConsoleApplication12
{
}

然后将其用作类型:

MyAlias test = new MyAlias();

1
你尝试过这个吗?它不会编译(假设List<T>是典型的);一个using别名总是需要完整的命名空间中指定。
Marc Gravell

1
@MarcGravell当然我测试了它,它肯定可以编译并且可以正常工作。
ken2k 2012年

2
@Jodrell我很少在中看到using指令namespace,主要是因为大多数工具都不把指令放在那里。
Marc Gravell

6
@ ken2k可以导出MyAlias并将其用于其他源文件吗?你是怎样做的?
gen

3
为什么这不是公认的答案?这实际上为问题提供了解决方案
AustinWBryan '18

19

您可以创建一个类型:

class ComplexList : List<Tuple<int,string,int>> { }

这与别名并不完全相同,但是在大多数情况下,您应该不会看到任何区别。


@ Serge-appTranslator,如果它与我的答案不同,但2分钟后。
Jodrell 2015年

2
@jodrell:哎呀!我想我们正在同时键入它。您刚刚赢得了比赛条件。顺便说一句,您的回答很好:我支持;-)
Serge Wautier

5
但是,如果类型是密封的(例如,您要“别名” KeyValuePair<K,V>),这将不起作用
Liam Dawson

2
由于子类化,这也可能使相等性检查失败。子类化!=别名。
Ryan The Leach

1
这很有用,但是有其局限性,例如,您不能将ComplexList分配给返回List <Tuple <int,string,int >>的函数的结果,也不能传递List <Tuple <int,string,int >>转换为带有ComplexList参数的函数。
凯文·霍尔特

16

那继承呢?

class ComplexList : List<Tuple<int, string, int>> {}

var complexList = new ComplexList();

这似乎是一个类似的概念,但是在C#中没有直接等同于基于类型的别名,只有名称空间别名

如果要避免代码中的类型名称冲突,则应采用名称空间别名。

如果要创建一个“新”类型,它是另一种类型的实例,则继承是一个选项。


5
在所有别名被密封的情况下,使用继承都会失败。
艾伦·克拉克·科普兰(Allen Clark Copeland Jr)2015年

7
但是,如果您这样做并声明一个void Foo(ComplexList a)方法,则Foo(new List<Tuple<int,string,int>>();尽管类型是同构的,但是将其称为as将是类型错误。
cemper93

1
继承是有好处的,除非您确实想要子类化的功能。在任何其他情况下,这都会增加开销,间接性,缓慢性和不可靠性。此外,您还被限制为不能将类与依赖给定类型的库一起使用。实际上,“别名”一词的含义要求类型仍然相同。换句话说,继承不是别名。别名将使您可以将对象传递到没有任何形式转换就不会共享别名的方法。
赞恩·克拉斯

@ZaneClaes,我从我的答案中删除了“(有好处。)”部分。我不同意别名一词的含义通常对类型系统具有任何特定含义。但是,C#继承不是Pascal别名的强等效项,但是没有强等效项。在Hindsight中,我更愿意接受被接受的答案。
Jodrell

1
@Jodrell根据“计算”中“别名”的字典定义:“引用一个项目并可以用来定位它的替代名称或标签。” 因此,根据定义,子类不能是别名,因为它没有引用或定位超类。它完全是一个新实体。在编译器级别,两者不是彼此等效或替代的版本。
赞恩·克莱斯

6

从最初问题中显示的语法来看,您似乎真的是在问如何用C#创建类,而不是如何给类型添加别名。

如果您想输入一个比名称更简单的名称List<Tuple<int,string,int>>,并且希望它是“全局”名称(即不是按文件),那么我将创建一个新类,该类继承了所述类,并且声明没有其他成员。像这样:

public class MyTrinaryTupleList: List<Tuple<int,string,int>> { }

这样就可以实现一个单一的管理位置,而无需额外的using语句。

但是,我也将更进一步,并冒险您可能不想要元组,而是想要另一个类,例如:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public int FavoriteNumber { get; set; }

    public Person() { }

    public Person(string name, int age, int favoriteNumber) 
    { 
        this.Name = name; 
        this.Age = age; 
        this.FavoriteNumber = favoriteNumber; 
    }
}

然后,对于您的列表类型,您可以执行以下操作:

public class PersonList: List<Person> { }

另外,如果您需要其他列表特定的帮助器属性或方法,也可以将它们添加到PersonList类。


4

是的,您可以这样做,但是您需要指定完整类型,即定义变为:

using ComplexList = System.Collections.Generic.List<System.Tuple<int,string,int>>;

这是针对每个文件指定的,与命名空间的using指令非常相似。

nitpick:通常,.NET中的类型是PascalCased。


不需要“完整类型”。如果其他using(例如using System.Collections.Generic;存在),则不需要“完整类型”。
ken2k 2012年

2
@ ken2k不正确;一个using别名总是需要它是合格的命名空间明确,即使现有的using指令将使其范围; 意思是:using var list = List<int>;不是有效的,即使经过using System.Collections.Generic;
马克·Gravell

1
实际上,如果别名是在名称空间范围内定义的,则不是必需的。
ken2k 2012年

1

只需简单使用即可:

using Foo = System.UInt16;

public class Test {
  public Foo Bar { get;set; }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.