有没有办法定义现有基本类型的C#强类型别名,如`string`或`int`?

也许我正在certificate我对C#或.NET框架的一些常用function的无知,但我想知道是否有一种本机支持的方法来创建一个类型别名,如EmailAddress ,它别名string但我可以扩展它与我自己的方法,如bool Validate()

我知道using x = Some.Type; 别名但这些不是全局的,也不提供类型安全性,即可以为当前文件中的使用别名换出普通string 。 我希望我的EmailAddress是它自己的类型,独立且不能与它所影的string类型互换。

我目前的解决方案是生成public sealed partial EmailAddress : IEquatable, IXmlSerializable带有T4模板的public sealed partial EmailAddress : IEquatable, IXmlSerializable类,生成样板隐式字符串转换运算符和其他类似的东西。 这对我来说很好,并给了我很大的灵活性,但在我的脑海里,我必须生成如此大量的样板代码才能做一些像创建强类型别名一样简单的事情。

也许除了代码生成之外,这是不可能的,但我很好奇其他人是否尝试过与他们的设计相似的东西以及你的经历。 如果没有别的,也许这可以作为假设未来版本的C#中的这种别名function的一个很好的用例。 谢谢!

编辑:我想要的真正价值是能够通过表示数据的不同类型/格式的原始类型获得类型安全性。 例如, EmailAddressSocialSecurityNumber以及PhoneNumber ,所有这些都使用string作为其基础类型,但它们本身并不是可互换的类型。 我认为这可以让你获得更具可读性和自我记录的代码,更不用说更多方法过载可能性的附加好处,而不是模棱两可。

如果您查看.NET Framework System.Uri是最接近的示例,类似于电子邮件地址。 在.NET中,模式是在类中包装某些东西并以这种方式添加约束。

添加强类型,为简单类型添加额外的约束是一个有趣的语言function,我相信一些function语言。 我无法回想起这种语言的名称,它可以让您在您的值中添加尺寸单位(例如英尺),并对等式进行维度分析以确保单位匹配。

关于为什么string被密封的一些背景

来自http://www.code-magazine.com/Article.aspx?quickid=0501091 :

罗里:嘿杰伊,你介意我问你几个问题吗? 我对某些事情已经好奇了。 首先,这是我本周所做的MSDN活动之一,为什么String密封? 注意:对于VB.NET程序员,Sealed = NotInheritable。

Jay:因为我们在String中做了很多魔术,试图确保我们可以优化比较之类的东西,尽可能快地制作它们。 所以,我们正在窃取指针和其他东西,以便标记出来。 只是给你一个例子,当我开始时我不知道这个,但是如果一个字符串中有一个连字符或一个撇号[那么]它的排序方式不同于它只有文本,并且排序算法如果您使用连字符或撇号,如果您正在进行全局感知排序非常复杂,那么我们实际上会标记该字符串是否具有该类型的行为。

罗里:所以,你所说的是,在字符串世界中,如果你没有密封字符串,如果人们试图将其子类化,那么就会有很大的空间来造成很大的破坏。

杰伊:没错。 它会改变对象的整个布局,所以我们无法播放我们播放的提示速度的技巧。

以下是您之前可能已经看过的CodeProject文章:

http://www.codeproject.com/KB/cs/expandSealed.aspx

所以是的,隐式运算符是你唯一的解决方案。

System.Net.Mail.MailAddress类是否符合您的需求,或者至少是“帮助”?

编辑:它不是明确的IEquatable或ISerializable,但你可以很容易地在你自己的包装器中添加它们。

看起来你至少有一个合理的C#knoledgde,所以我的答案可能看起来很愚蠢,但你想要的是“类型层次结构”,编码String类的人想阻止你使用这个“OOfunction”,所以他们做了Stringclass级密封,这就是为什么你不能做你想要的。 最好的方法就是你现在就开始:创建自己的类型并隐式转换为String。

我想你想使用扩展方法。 它们允许您扩展类function,而无需创建新的派生类型。

我想我不明白为什么你想要同时拥有强类型和隐式字符串转换。 对我来说,一个人排除了另一个。

我试图为int解决同样的问题(你在标题中提到int,但在问题中没有提到)。 我发现声明一个枚举会给你一个类型安全的整数,需要从/显式地转换为int。

更新

枚举可能不适用于开放式集合,但仍可以这种方式使用。 此示例来自编译实验,以区分数据库中多个表的ID列:

  enum ProcID { Unassigned = 0 } enum TenderID { Unassigned = 0 } void Test() { ProcID p = 0; TenderID t = 0; <-- 0 is assignable to every enum p = (ProcID)3; <-- need to explicitly convert if (p == t) <-- operator == cannot be applied t = -1; <-- cannot implicitly convert DoProc(p); DoProc(t); <-- no overloaded method found DoTender(t); } void DoProc(ProcID p) { } void DoTender(TenderID t) { } 

我用这个课程来满足相同的需求。 这个是“int”类型(我也有一个“字符串”):

 public class NamedInt : IComparable, IEquatable { internal int Value { get; } protected NamedInt() { } protected NamedInt(int val) { Value = val; } protected NamedInt(string val) { Value = Convert.ToInt32(val); } public static implicit operator int (NamedInt val) { return val.Value; } public static bool operator ==(NamedInt a, int b) { return a?.Value == b; } public static bool operator ==(NamedInt a, NamedInt b) { return a?.Value == b?.Value; } public static bool operator !=(NamedInt a, int b) { return !(a==b); } public static bool operator !=(NamedInt a, NamedInt b) { return !(a==b); } public bool Equals(int other) { return Equals(new NamedInt(other)); } public override bool Equals(object other) { if ((other.GetType() != GetType() && other.GetType() != typeof(string))) return false; return Equals(new NamedInt(other.ToString())); } private bool Equals(NamedInt other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Equals(Value, other.Value); } public int CompareTo(int other) { return Value - other; } public int CompareTo(NamedInt other) { return Value - other.Value; } public override int GetHashCode() { return Value.GetHashCode(); } public override string ToString() { return Value.ToString(); } } 

并在你的情况下消费它:

 public class MyStronglyTypedInt: NamedInt { public MyStronglyTypedInt(int value) : base(value) { // Your validation can go here } public static implicit operator MyStronglyTypedInt(int value) { return new MyStronglyTypedInt(value); } public bool Validate() { // Your validation can go here } } 

如果你需要能够序列化它(Newtonsoft.Json),请告诉我,我将添加代码。