17

情况

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

过去的情况是,它的许多方法将它们作为 s 相互传递string,但是很难准确地跟踪每种方法所期望的路径类型。

所需的修复

所以我们本质上想要typedef四种不同的类型stringRemoteRelative、、、LocalRelative和。这样,静态类型检查器可以帮助开发人员确保他们提供和期望s 具有正确的语义。RemoteAbsoluteLocalAbsolutestring

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

实际修复

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

public struct LocalAbsolutePath {
    public readonly string path;
    public LocalAbsolutePath(string path) {
        this.path = path;
    }
}

这主要是可行的,但最终会增加一些不受欢迎的冗长。

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

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

4

5 回答 5

15

你的解决方案很好。你可以通过添加类型转换来对抗额外的冗长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;
    }
}
于 2012-04-27T19:29:59.613 回答
5

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

虽然我不觉得这var myPath = new LocalAbsolutePath("path")真的比 更冗长var myPath = "path",因为它缺乏简洁性,它弥补了明确性,但如果你真的想要,你可以在你的类和字符串之间实现隐式转换运算符,并拥有这个工作:

 public static implicit operator LocalAbsolutePath(string path)
 {
     return new LocalAbsolutePath(path);
 }

现在你可以这样做:

LocalAbsolutePath myPath = "Path String";
于 2012-04-27T19:31:30.160 回答
1

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

这是你将如何使用它:

class CustomerId : LikeType<string>
{
    public CustomerId(string id) : base(id) { }
}

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

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.
}
于 2015-11-24T01:04:24.620 回答
0

由于我在我正在从事的项目中设定了相同的目标,并且我从这里的答案中受益匪浅,我想我会分享我最终得到的解决方案。处理 null,尤其是在单元测试断言中,几乎让我发疯。以下当然会失败:

string someStringVar = null;
MyStringType myStringType = new MyStringType(someStringVar);
MyStringType myStringTypeNull = null;
Assert.AreEqual(myStringType, myStringTypeNull);

使用静态 Parse() 代替公共构造函数更令人满意,因为它让我返回 null。这通过:

string someStringVar = null;
MyStringType myStringType = MyStringType.Parse(someStringVar);
MyStringType myStringTypeNull = null;
Assert.AreEqual(myStringType, myStringTypeNull);

此外,我不希望从字符串隐式转换为 MyStringType - 在我看来,这首先消除了一些有意识的编码器好处。允许从字符串进行隐式转换意味着调用带有 MyStringType 参数的方法将接受字符串,而我不希望这样,因为带有大量字符串参数的方法很容易出错。隐式完成的反向转换对我来说更有意义。

最后,我认为这是一个易于重用的泛型的理想案例。

无论如何,这就是我最终得到的结果:

public class StringType<T> where T:class
{
    private readonly string _str;

    protected StringType(string str)
    {
        _str = str;
    }

    public static implicit operator string(StringType<T> obj)
    {
        return obj == null ? null : obj._str;
    }

    public override string ToString()
    {
        return _str;
    }

    public override int GetHashCode()
    {
        return _str.GetHashCode();
    }
}


public class MyStringType : StringType<MyStringType>
{
    protected MyStringType(string str) : base(str) { }

    public static MyStringType Parse(object obj)
    {
        var str = obj is string ? (string)obj : (obj == null ? null : obj.ToString());
        return str == null ? null : new MyStringType(str);
    }
}

当然欢迎评论/改进/简化!

于 2013-05-09T14:03:43.227 回答
-2

也许我在这里叫错了树,但typedef据我所知,它在 C# 中被实现为类型别名。设置类型别名就像这样简单:

using LocalAbsolutePath = System.String;

然后您可以开始使用LocalAbsolutePath作为有效类型。或多或少是这样的:

LocalAbsolutePath thisPath = "c:\\thisPath";

根据您的帖子,我感觉这就是您要找的东西。希望我是对的……!

于 2012-04-27T19:48:37.727 回答