c#中typedef或子类化字符串的替代方法

sbl*_*lom 14 c# syntax typedef

情况

我有一个类在内部处理许多不同类型的文件路径:一些是本地的,一些是远程的; 一些亲戚,一些绝对.

过去,它的许多方法都将它们作为strings 传递给彼此,但是很难跟踪每种方法所期望的确切路径类型.

理想的修复

所以我们基本上是想typedef四种不同的类型string:RemoteRelative,LocalRelative,RemoteAbsolute,和LocalAbsolute.通过这种方式,静态类型检查器可以帮助开发人员确保他们提供并期望string具有正确的语义.

不幸的stringsealed,在BCL中,所以我们不能通过简单的继承来做到这一点.而且没有简单的typedef,所以我们也不能这样做.

实际修复

我最终创建了四个不同的简单类,每个类都包含一个readonly string.

public struct LocalAbsolutePath {
    public readonly string path;
    public LocalAbsolutePath(string path) {
        this.path = path;
    }
}
Run Code Online (Sandbox Code Playgroud)

这大部分都有效,但最终会增加一些不受欢迎的冗长.

问题:我是否忽略了任何自然适合简单C#语法的替代方案?

就像我上面提到的,C风格typedef string LocalAbsolutePath;甚至是F#风格type LocalAbsolutePath = string都是我的梦想.但即使是自定义类的方向步骤也会很棒.

das*_*ght 14

你的解决方案很好.您可以通过添加类型转换来对抗额外的详细程度string,让您可以LocalAbsolutePath在任何地方使用string.

public struct LocalAbsolutePath { // Making it a class would be OK too
    private readonly string path; // <<=== It is now private
    public LocalAbsolutePath(string path) {
        this.path = path;
    }
    public static implicit operator string(LocalAbsolutePath p) {
        return p.path;
    }
}
Run Code Online (Sandbox Code Playgroud)


Avn*_*tan 5

你应该做的是保持你当前的方法为你的路径类型创建四个不同的类(甚至让它们继承相同的基类),这样你就可以限制方法只接收这四个Path对象中的一个.

虽然我觉得它var myPath = new LocalAbsolutePath("path")真的不是那么冗长var myPath = "path",因为它简洁而缺乏它在显性上的弥补,但是如果你真的想要,你可以在你的类和字符串之间实现隐式的转换操作符,并拥有它工作:

 public static implicit operator LocalAbsolutePath(string path)
 {
     return new LocalAbsolutePath(path);
 }
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

LocalAbsolutePath myPath = "Path String";
Run Code Online (Sandbox Code Playgroud)


Mat*_*ein 1

我创建了一个名为LikeType的 NuGet 包,它在 C# 类中提供typedef类似行为。

您将这样使用它:

class CustomerId : LikeType<string>
{
    public CustomerId(string id) : base(id) { }
}
Run Code Online (Sandbox Code Playgroud)

以下是该类型的行为方式:

void ShowTypeBehavior()
{
    var customerId = new CustomerId("cust-001"); // create instance with given backing value
    string custIdValue = customerId; // implicit cast from class to backing type, sets 'custIdValue' to "cust-001"

    var otherCustomerId = new CustomerId("cust-002");
    var areEqual = customerId == otherCustomerId; // false
    var areNotEqual = customerId != otherCustomerId; // true
    var areEqualUsingMethod = customerId.Equals(otherCustomerId); // false

    var customerIdCopy = new CustomerId("cust-001"); // create separate instance with same backing value
    var isCopyEqual = customerId == customerIdCopy; // true. Instances are considered equal if their backing values are equal.
}
Run Code Online (Sandbox Code Playgroud)