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

时间:2012-04-27 19:23:21

标签: c# syntax typedef

情况

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

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

所需的修复

因此,我们基本上希望typedef四种不同类型stringRemoteRelativeLocalRelativeRemoteAbsoluteLocalAbsolute。这样,静态类型检查器可以帮助开发人员确保他们提供并期望string具有正确的语义。

不幸的是,string在BCL中是sealed,因此我们无法通过简单继承来执行此操作。而且没有简单的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 个答案:

答案 0 :(得分: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;
    }
}

答案 1 :(得分: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";

答案 2 :(得分: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);
    }
}

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

答案 3 :(得分:-2)

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

using LocalAbsolutePath = System.String;

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

LocalAbsolutePath thisPath = "c:\\thisPath";

根据你的帖子,我觉得这就是你要找的东西。希望我是对的......!