在运行时设置常量/枚举?

时间:2013-09-17 08:43:18

标签: c#

这似乎是一个奇怪的要求,我很欣赏,但情况就是这样:

我有一个程序,它依赖于读取少量文件。这些文件的名称如下:foo_bar_BAZ.txt其中BAZ是项目的名称,直到运行时才知道。但是,对于整个程序的执行,它不会改变。

我希望有一个枚举列表,用于存储所有文件名。到目前为止,我使用了密封类,如下:

public sealed class SQLFile
{
    private readonly String name;
    private readonly String value;

    public static readonly SQLFile CrByAuthors = new SQLFile("Changes_CR_By_Authors_%project_name%.txt", "CrByAuthors");
    public static readonly SQLFile DocumentCrMetrics = new SQLFile("Changes_Document_CR_Output_%project_name%.txt", "DocumentCrMetrics");
    [...]


    private SQLFile(String value, String name)
    {
        this.name = name;
        this.value = value;
    }

    public String ToString(string projectName)
    {
        return this.value.Replace("%project_name%", projectName);
    }
}

正如您所看到的,这取决于我每次要访问文件名时都提供项目名称变量,即使该文件名从运行时开始到结束都非常不变。

有没有更优雅的方式处理这种情况?

3 个答案:

答案 0 :(得分:0)

一个简单的解决方案是使用具有ProjectName属性的静态类。在启动应用程序期间设置此属性的值。然后你的班级可以使用那个属性。

答案 1 :(得分:0)

SQLFile添加静态属性,类似

public sealed class SQLFile
{  
    //...
    private static string sProjectName;
    public static string ProjectName
    {
        get
        {
            return sProjectName;
        }
        set
        {
            //optionally, you could prevent updates with:
            //if (string.IsNullOrEmpty(sProjectName))
            sProjectName= value;
            //else throw Exception("ProjectName was already set!");
        }
}

答案 2 :(得分:0)

[编辑 - 我读的代码有点太快,所以这就是我的意思:]

(名称不当的IMHO)方法ToString的目的是返回与某个项目名称对应的文件的名称。这没有任何问题,虽然它可能是一个可能属于一个分离的阶级的责任。

例如,您可以重构代码以更清楚地表达其意图:

interface ISqlFileNameProvider 
{
     string SqlFilename { get; }
}

然后有一个简单的(“穷人”)实现:

public class SimpleSqlFileNameProvider : ISqlFileNameProvider
{
    private readonly string _filename;
    public SimpleSqlFileNameProvider(string filename)
    {
        _filename = filename;
    }

    public string SqlFilename
    {
        get { return _filename; }
    }
}

然后从这里派生出专门的实现:

public class TemplateSqlFileNameProvider : SimpleSqlFileNameProvider
{
    public TemplateSqlFileNameProvider(string template, string projectName)
        : base(template.Replace("%project_name%", projectName))
    { }
}

public class CrByAuthorsFileNameProvider : TemplateSqlFileNameProvider
{
    public CrByAuthorsFileNameProvider(string projectName)
        : base("Changes_CR_By_Authors_%project_name%.txt", projectName)
    { }
}

public class DocumentCrMetricsFileNameProvider : TemplateSqlFileNameProvider
{
    public DocumentCrMetricsFileNameProvider(string projectName)
        : base("Changes_Document_CR_Output_%project_name%.txt", projectName)
    { }
}

首先,请注意projectName仍然是这些专业类的constructor的参数。这里没有全局变量。接下来,即使您已经为项目添加了一些管道代码,也可以更轻松地将类拆分为更简单的测试:您可以创建一个模拟的ISqlFileNameProvider实现并返回您喜欢的任何内容来测试其余的功能无需写入实际数据文件。

我当然建议不要使用全球财产。您可以将项目名称指定为构造函数参数,这意味着您可以轻松地测试您的类的行为方式。即使您认为它会在项目生命周期中发生变化,您也可以轻松地遇到暂时需要在运行时切换项目名称的场景。我建议不要使用全局变量。