Is there a way to define C# strongly-typed aliases

2019-04-03 15:40发布

Perhaps I am demonstrating my ignorance of some oft-used feautre of C# or the .NET framework, but I would like to know if there is a natively-supported way to create a type alias like EmailAddress which aliases string but such that I can extend it with my own methods like bool Validate()?

I know of the using x = Some.Type; aliases but these are not global nor do they provide type safety, i.e. one could swap out an ordinary string for the using alias in the current file. I would like my EmailAddress to be its own type, independent and not interchangeable with the string type that it shadows.

My current solution is to generate public sealed partial EmailAddress : IEquatable<EmailAddress>, IXmlSerializable classes with a T4 template generating the boilerplate implicit string conversion operators and other such things. This is fine with me for now and gives me a lot of flexibility but at the back of my mind it seems silly that I have to generate such copious amounts of boilerplate code to do something as simple as creating a strong type alias.

Maybe this is not possible other than with code generation, but I am curious if others have attempted something similar with their designs and what your experiences have been. If nothing else, perhaps this could serve as a good use-case for such an alias feature in a hypothetical future version of C#. Thanks!

EDIT: The real value that I want out of this is to be able to get type safety with primitive types that represent different types/formats for data. For instance, an EmailAddress and a SocialSecurityNumber and a PhoneNumber, all of which use string as their underlying type but which are not interchangeable types in and of themselves. I think this gets you much more readable and self-documenting code, not to mention added benefits of more method overload possibilities that are less ambiguous.

7条回答
一纸荒年 Trace。
2楼-- · 2019-04-03 16:27

I guess I do not get why you want to have both strong types AND implicit string conversion at the same time. For me, one rules out the other.

I tried to solve the same problem for ints (you mention int in the title, but not in the question). I found that declaring an enum gives you a type-safe integer which needs to be explicitly cast from/to int.

Update

Enums may not be intended for open sets, but can still be used in such a way. This sample is from a compilation experiment to distinguish between the ID columns of several tables in a database:

    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)
    {
    }
查看更多
登录 后发表回答