【问题标题】:Defining type aliases定义类型别名
【发布时间】:2012-03-04 16:55:52
【问题描述】:

我发现 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# 是否支持实现此目的的方法?

【问题讨论】:

标签: c# types


【解决方案1】:

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

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();

【讨论】:

  • 你试过了吗?它不会编译(假设List&lt;T&gt; 是典型的); using 别名始终需要指定完整的命名空间。
  • @MarcGravell 当然我测试过了,它绝对可以编译并且工作正常。
  • @Jodrell 我很少在namespace 中看到using 指令,主要是因为大多数工具都没有把它们放在那。
  • @ken2k 你能导出 MyAlias 并在其他源文件中使用它吗?你是怎么做到的?
  • 为什么这不是公认的答案?这实际上提供了问题的解决方案
【解决方案2】:

这并不是你在 Pascal 中所做的事情,但你可以使用 using-directive。看看这里how to use it

例子:

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();
        }
    }
}

【讨论】:

  • 次要点:文件顶部的using指令,而不是语句; “使用声明”是涉及IDisposable 的事情。特别是,这是一个“使用别名”。
  • 注意:另外,如果您只是将类命名为“MyList”,那么当然不再需要 using 指令(这也解决了原来的问题)。
  • 链接指向较旧的文档页面。虽然仍然有效且准确(并且其中包含以下链接),但如果旧页面被删除,这里是指向新页面的链接。 docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
  • 这对命名元组有用吗?我不能让它工作。我尝试的是:using MyType = (TypeA a, TypeB b);。我想我可以使用未命名的元组并且它会起作用,但我真的想要名称而不是Item1Item2。 :(
【解决方案3】:

你可以创建一个类型:

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

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

【讨论】:

  • @jodrell:哎哟!我猜我们是同时打字的。你刚刚赢得了比赛条件。顺便说一句,您的回答非常好:我赞成;-)
  • 这不起作用,但是,如果类型是密封的(例如,你试图“别名”KeyValuePair&lt;K,V&gt;
  • 由于子类化,这也可能导致相等检查失败。子类化!=别名。
  • 这很有用,但有其局限性,例如您不能将 ComplexList 分配给返回 List> 的函数的结果,也不能将 List> 传递给具有 ComplexList 参数的函数.
  • 很好,但它不会继承构造函数
【解决方案4】:

继承呢?

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

var complexList = new ComplexList();

这似乎是一个类似的概念,但在 C# 中没有直接等效于基于类型的别名,只有 namespace aliases

如果您想避免代码中的类型名称冲突,命名空间别名是可行的方法。

如果你想创建一个“是”另一种类型的实例的新类型,继承是一种选择。

【讨论】:

  • 除非使用继承,否则在别名引用的类型是密封的所有情况下都会失败。
  • 但是,如果你这样做并声明一个void Foo(ComplexList a) 方法,将其调用为Foo(new List&lt;Tuple&lt;int,string,int&gt;&gt;(); 将是一个类型错误,尽管类型是同构的。
  • 继承远没有好处,除非你真的想要子类化的特性。在任何其他情况下,这都会增加开销、间接性、缓慢性和不可靠性。此外,您还被限制不能将类与依赖于给定类型的库一起使用。实际上,“别名”一词的含义要求类型仍然相同。换句话说,继承不是别名。别名将允许您将对象传递到不共享别名的方法中,而无需任何形式的转换。
  • @ZaneClaes,我已经从我的答案中删除了“(有好处。)”部分。我不同意别名一词的含义通常对类型系统具有任何特定含义。然而,C# 继承不是 Pascal 别名的强等价物,但没有强等价物。事后看来,我更倾向于接受已接受的答案。
  • @Jodrell 根据“计算”中“别名”的字典定义:“一个替代名称或标签,指的是 [...] 一个项目,可用于定位它。”因此,根据定义,子类不能是别名,因为它不引用或定位超类;它完全是一个新实体。在编译器级别,两者不是等价或替代版本。
【解决方案5】:

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

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

这是为每个文件指定的,很像命名空间的 using 指令。

nitpick:按照惯例,.NET 中的类型是 PascalCased。

【讨论】:

  • “完整类型”不是必需的。如果存在其他using(例如using System.Collections.Generic;),则不需要“完整类型”。
  • @ken2k 不正确; using 别名总是要求它明确地被命名空间限定,即使现有的 using 指令会将其纳入范围;含义:using var list = List&lt;int&gt;;无效有效,即使在using System.Collections.Generic;之后
  • 如果别名实际上是在命名空间范围内定义的,则不需要。
【解决方案6】:

从最初问题中显示的语法来看,您实际上只是在问如何在 C# 中创建一个类,而不是如何为类型设置别名。

如果您想要一个比List&lt;Tuple&lt;int,string,int&gt;&gt; 更简单的名称,并且您希望它是“全局的”(即不是每个文件),我将创建一个继承该类并且不声明其他成员的新类。像这样:

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 类中。

【讨论】:

    【解决方案7】:

    只需简单的使用即可:

    using Foo = System.UInt16;
    
    public class Test {
      public Foo Bar { get;set; }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-10
      • 2019-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-15
      • 1970-01-01
      • 2021-11-17
      相关资源
      最近更新 更多