1

完全出于节省代码输入的兴趣,我想找到某种方法将文本附加到另一个类返回的成员。这可能没有意义,所以举个例子。我正在研究的是一个管理测试数据的类:

public class TestFiles
{
    private const string File1RelativePath = @"TestData\File1.xml";
    private const string File2RelativePath = @"TestData\File2.xml";

    private static string RootPath()
    {
        // don't know the deployment location until runtime 
        return Some_DirectoryName_Determined_At_Run_Time_Returned_BySomeOtherModule();
    }

    public static string File1
    {
        get { return Path.Combine(RootPath() + File1RelativePath); }
    }

    public static string File2
    {
        get { return Path.Combine(RootPath() + File2RelativePath); }
    }
}   

这个类完全符合我的要求,我可以简单地通过以下方式调用它:

String FileToUseForTest = TestFiles.File1;

问题是我很懒,当我添加更多文件时,我必须在两个地方进行:常量字符串和获取属性。也许我可以在 getter 中包含字符串文字,但即便如此,我也必须在每个 getter 中调用 Path.Combine(RootPath() ... ,这对我来说工作量太大了。

因此,尝试另一种方法,由于以下原因,该方法不起作用:

public class TestFiles
{
    public class FileRelativePaths
    {
        private const string File1RelativePath = @"TestData\File1.xml";
        private const string File2RelativePath = @"TestData\File2.xml";
    }

    private static FileRelativePaths relPaths = new RulePackages();

    FileRelativePaths FullPaths
    {
        get { return relPaths; }
    }

    private static string RootPath()
    {
        // No longer called, but somehow need to find a way to append to paths returned in FullPaths
        return Some_DirectoryName_Determined_At_Run_Time_Returned_BySomeOtherModule();
    }
}   

这几乎可行,我得到了强类型,调用者可以通过

String FileToUseForTest = TestFiles.FullPaths.File1;

但问题是这只是给了我相对路径,我真的想在返回的字符串中附加一些代码(通过使用方法 RootPath())。

那么,有什么方法可以让它工作,同时仍然具有强类型并将代码长度保持在最低限度?我有点接受使用上面的第一种方法,但我想我会问是否有创造性的解决方案。

4

6 回答 6

1

如何使用运算符重载来执行包含根路径的隐式转换?

class Program
{
    static void Main(string[] args)
    {
        RelativePath relative = @"Relative\Path\One";

        Console.WriteLine(relative.Path);
        string path = relative;
        Console.WriteLine(path);

        Console.ReadLine();
    }
}

public class RelativePath
{

    public static string RootPath()
    {
        return @"C:\MyRootPath\";
    }

    public string Path
    {
        get;
        protected set;
    }

    public RelativePath(string relativePath)
    {
        this.Path = relativePath;
    }

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

    public static implicit operator string(RelativePath relativePath)
    {
        return System.IO.Path.Combine(RootPath(), relativePath.Path);
    }

}
于 2012-04-09T18:37:56.380 回答
1

就个人而言,我只是让自己不得不在两个地方进行更改。这是我不太喜欢的另一种选择,但据我了解,它满足您的标准:

public enum XmlFile{
    File1,
    File2
};

public static class TestFiles{
    const string RelativeDirectory = @"TestData";
    const string XmlExtension = @"xml";
    static string RootPath {
        get
        {
            return Some_DirectoryName_Determined_At_Run_Time_Returned_BySomeOtherModule();
        }
    }

    //overload as necessary for other extensions or pass it as an additional parameter
    public static string GetFullPath(XmlFile file){
        return string.Format(@"{0}{1}\{2}.{3}", RootPath, RelativeDirectory, file, XmlExtension);
    }
}

这个片段有一些不幸的副作用:

  • 使用约定将枚举成员与文件名相关联
  • 依赖于枚举的 ToString()
  • 假设 RelativeDirectory 始终相同(否则,您将需要进一步的约定来适应)
于 2012-04-09T19:09:00.343 回答
0

只需使用一个小的辅助函数...

private static string fixupPath (string dir)
{
    return Path.Combine(RootPath() + dir); 

}

public static string File1
{
    get { return fixupPath(File1RelativePath); }
}

如果您真的想优化击键而不是可维护性,请使用较短的函数名称。

于 2012-04-09T18:32:49.320 回答
0

这样的事情怎么样?注意,前面有未经测试的代码:

public enum TestFileType {
    File1,
    File2,
}

public class TestFiles
{
    private static Dictionary<TestFileType, String> filePaths = new Dictionary<TestFileType, String> 
        { 
            { TestFileType.File1, @"TestData\File1.xml" }, 
            { TestFileType.File2, @"TestData\File2.xml" } 
        };

    public static String GetFile(TestFileType fType) {
        return Path.Combine(RootPath() + filePaths[fType]);
    }
}

// Use thus: 
TestFiles.GetFile(TestFileType.File1);
于 2012-04-09T18:39:24.960 回答
0

有几件事浮现在脑海中。首先,你可以有一个枚举、一个字典和一个“get”函数,而不是离散属性:

public enum TestFile { File1, File2 };

public class TestFiles {

  private static Dictionary<TestFile,string> _testFiles = new Dictionary<TestFile,string> {
    { TestFile.File1, @"TestData\File1.xml" },
    { TestFile.File2, @"TestData\File2.xml" },
  };

  public string RootPath() {
    return @"C:\";
  }

  public string Get( TestFile tf ) {
    return Path.Combine( RootPath(), _testFiles[tf] );
  }

  // even better, you can override the array indexing operator
  public string this[TestFile tf] {
    get { 
        return Path.Combine( RootPath(), _testFiles[tf] );
    }
  }
}

如果你想抽象出重复的Path.Combine代码,你总是可以使用一个辅助类,尽管我怀疑你会在这里获得很多。不过,它可能会增加可读性:

public static class TestFileHelper {
    public static string RootPath() {
      return @"C:\";
    }

    public static string RootedAtTestDir( this string s ) {
        return Path.Combine( RootPath(), s );
    }
}

然后,不用Path.Combine到处打电话,你可以写:

return _testFiles[tf].RootedAtTestDir();
于 2012-04-09T18:41:35.150 回答
0

这实际上可能是扩展的一个很好的用例。您可以将其添加到测试程序集/文件中,然后在需要的地方引用它:

public static class TestExtensions
{
    private static string RootPath = @"C:\Some\Root\Path";
    public static string AddRoot(this string path)
    {
        return Path.Combine(RootPath, path);
    }
}

另一种选择是也使用字典,以防您要定义多个“根”,这样您就可以指定两件事:路径和根键。

public static class TestExtensions
{
    private static Dictionary<string, string> RootPaths = new Dictionary<string, string>();

    public static void RegisterRoot(string rootKey, string rootPath)
    {
        // Omitted null checking, but should do it.
        RootPaths[rootKey] = rootPath;
    }

    public static string AddRoot(this string path, string rootKey)
    {
        return Path.Combine(RootPaths[rootKey], path);
    }
}

用法很简单。只需在任何字符串实例上调用扩展方法。IE:

// Single root version.
TestFiles.File1.AddRoot(); 
// String literal...
@"Relative\Path\File.xml".AddRoot();
// Dictionary root version.
TestExtensions.RegisterRoot("testRoot", @"C:\Some\Test\Directory");
TestFiles.File1.AddRoot("testRoot"); 

希望有帮助。

于 2012-04-09T19:12:57.270 回答