2015-04-25 263 views
4

我目前正在開發一個軟件,用戶不應該能夠訪問它的後端,但應該仍然能夠輕鬆更改配置/設置應用。 我決定最好的方法是定製的「配置文件(.cfg)」位於最終版本的根目錄。 .cfg文件的 簡單的例子:通過自定義屬性設置特定屬性的值

serveraddress='10.10.10.10' 
serverport='1234' 
servertimeout='15000' 

因爲我想要的配置文件來輕鬆擴展,我決定用一些自定義的屬性和一些簡單的LINQ。 這樣做的工作就像我期望的那樣,但是因爲我仍然是.net中的新手,所以我恐怕沒有采用最好的方法,而我的問題是這樣的: 有什麼可以改進的嗎? 還是隻有一個更好的方法呢?

這是我的代碼,用於讀取配置文件並將值分配給相應的屬性。

ConfigFileHandler.cs

public void ReadConfigFile() 
    { 
     var cfgFile = new ConfigFile(); 
     var configLines = File.ReadAllLines("configfile.cfg"); 
     var testList = configLines.Select(line => line.Split('=')) 
      .Select(splitString => new Tuple<string, string>(splitString[0], splitString[1].Replace("'", ""))) 
      .ToList(); 
     foreach (var prop in typeof(ConfigFile).GetProperties()) 
     { 
      var attrs = (ConfigFileFieldAttribute[])prop.GetCustomAttributes 
       (typeof(ConfigFileFieldAttribute), false); 
      foreach (var t in from attr in attrs from t in testList where t.Item1 == attr.Name select t) 
      { 
       prop.SetValue(cfgFile, t.Item2); 
      } 
     } 
    } 

ConfigFile.cs

class ConfigFile 
    { 
     private static string _serverAddress; 
     private static int _serverPort; 
     private static int _serverTimeout; 

     [ConfigFileField(@"serveraddress")] 
     public string ServerAddress 
     { 
      get { return _serverAddress; } 
      set { _serverAddress= value; } 
     } 

     [ConfigFileField(@"serverport")] 
     public string ServerPort 
     { 
      get { return _serverPort.ToString(); } 
      set { _serverPort= int.Parse(value); } 
     } 

     [ConfigFileField(@"servertimeout")] 
     public string ServerTimeout 
     { 
      get { return _serverTimeout.ToString(); } 
      set { _serverTimeout= int.Parse(value); } 
     } 
    } 

任何提示上寫更好看的代碼將不勝感激!


更新: 感謝您的所有反饋。

下面是最後的課程! https://dotnetfiddle.net/bPMnJA一個活生生的例子

請注意,這是C#6.0

ConfigFileHandler.cs

public class ConfigFileHandler 
{ 
    public void ReadConfigFile() 
    { 
     var configLines = File.ReadAllLines("configfile.cfg"); 
     var configDictionary = configLines.Select(line => line.Split('=')) 
     .Select(splitString => new Tuple<string, string>(splitString[0],  splitString[1].Replace("'", ""))) 
     .ToDictionary(kvp => kvp.Item1, kvp => kvp.Item2); 
     ConfigFile.SetDictionary(configDictionary); 
    } 
} 

ConfigFile.cs

public class ConfigFile 
{ 
    private static Dictionary<string, string> _configDictionary; 

    public string ServerAddress => PullValueFromConfig<string>("serveraddress", "10.1.1.10"); 

    public int ServerPort => PullValueFromConfig<int>("serverport", "3306"); 

    public long ServerTimeout => PullValueFromConfig<long>("servertimeout", ""); 


    private static T PullValueFromConfig<T>(string key, string defaultValue) 
    { 
     string value; 
     if (_configDictionary.TryGetValue(key, out value) && value.Length > 0) 
      return (T) Convert.ChangeType(value, typeof (T)); 
     return (T) Convert.ChangeType(defaultValue, typeof (T)); 

    } 

    public static void SetDictionary(Dictionary<string, string> configValues) 
    { 
     _configDictionary = configValues; 
    } 
} 
+0

你爲什麼重新發明輪子?配置文件是一個解決的問題。您可以使用例如XML或JSON序列化或.NET .config文件 –

+1

感謝您的評論Thomas Levesque。我知道這些,但我決定不去使用它的原因是,應該能夠更改配置文件的用戶沒有關於這些格式的經驗,我正試圖使配置文件儘可能簡單。 –

+0

我編輯了你的標題。請參閱:「[應該在其標題中包含」標籤「](http://meta.stackexchange.com/questions/19190/)」,其中的共識是「不,他們不應該」。 –

回答

3

你可以保留你的配置文件的簡單並通過將值加載到字典中然後將其傳遞到ConfigFile類中來擺脫嵌套循環。

public static void ReadConfigFile() 
    { 
     var configLines = File.ReadAllLines("configfile.cfg"); 
     var testList = configLines.Select(line => line.Split('=')) 
      .Select(splitString => new Tuple<string, string>(splitString[0], splitString[1].Replace("'", ""))) 
      .ToDictionary(kvp => kvp.Item1, kvp => kvp.Item2); 

     var cfgFile = new ConfigFile(testList); 
    } 

新ConfigFile實現類:

class ConfigFile 
{ 
    private Dictionary<string, string> _configDictionary; 

    public ConfigFile(Dictionary<string, string> configValues) 
    { 
     _configDictionary = configValues; 
    } 

    public string ServerAddress 
    { 
     get { return PullValueFromConfig("serveraddress", "192.168.1.1"); } 
    } 

    public string ServerPort 
    { 
     get { return PullValueFromConfig("serverport", "80"); } 
    } 

    public string ServerTimeout 
    { 
     get { return PullValueFromConfig("servertimeout", "900"); } 
    } 

    private string PullValueFromConfig(string key, string defaultValue) 
    { 
      string value; 
      if (_configDictionary.TryGetValue(key, out value)) 
       return value; 
      return defaultValue; 
    } 
} 
+1

謝謝phil!這確實是一個非常好的方法!只需添加一些靜態值,因爲ConfigFile數據類將在很多地方初始化。第二個構造函數沒有做任何事情,它看起來很完美!如果我有任何問題,我會隨時隨地處理並告訴你! :) –

1

我決定使用自定義的 「配置文件(.cfg)」 坐落在最終版本的根。

好主意。要獲得更簡潔的代碼,可以使用JSONJSON.NET進行反序列化,並將讀寫寫入ConfigFile類。這是一個例子,live as a fiddle

ConfigFile類負責自行加載和保存,並使用JSON.NET進行反序列化。

public class ConfigFile 
{ 
    private readonly static string path = "somePath.json"; 
    public string ServerAddress { get; set; } 
    public string ServerPort { get; set; } 
    public string ServerTimeout { get; set; } 
    public void Save() 
    { 
     var json = JsonConvert.SerializeObject(this, Formatting.Indented); 
     File.WriteAllText(path, json) 
    } 
    public static ConfigFile Load() 
    { 
     var json = File.ReadAllText(path); 
     return JsonConvert.DeserializeObject<ConfigFile>(json); 
    } 
} 

下面介紹如何使用它來加載文件,更改其屬性並保存。

ConfigFile f = ConfigFile.Load(); 
f.ServerAddress = "0.0.0.0"; 
f.ServerPort = "8080"; 
f.ServerTimeout = "400"; 
f.Save(); 

我們使用.json文件擴展名作爲慣例。你仍然可以使用.cfg,因爲它只是帶有特定語法的純文本。從上面的使用得到的配置文件內容是這樣的:

{ 
    "ServerAddress":"0.0.0.0", 
    "ServerPort":"8080", 
    "ServerTimeout":"400" 
} 

你可以告訴你的客戶「只更改數字」。就我而言,你的方法很好。以上只是一個更清晰的實施。

+0

謝謝你的建議肖恩!我會試試看!我認爲唯一的問題是配置處理程序嚴格依賴於配置文件的格式是正確的,糾正我,如果我錯了。如果用戶錯誤地不遵循JSON格式,那麼這可能會產生一個問題,該格式根本不會分配任何行? –

+0

@zatixiz是的。如果用戶沒有遵循JSON格式,這將是一個問題。 JSON比你使用的格式更復雜,所以它更像JSON,用戶會犯一個錯誤。 –

+1

我以爲是。但是,如果任何參數需要它是數組中的值,那麼JSON會簡化很多,所以JSON是一定要記住的東西!再次感謝@Shaun –

1

首先,我會做菲爾的工作,並將您的測試列表存儲在字典中。

var configLines = File.ReadAllLines("configfile.cfg"); 
var testDict = configLines.Select(line => line.Split('=', 2)) 
          .ToDictionary(s => s[0], s => s[1].Replace("'", "")); 

然後你就可以清理屬性賦值LINQ一點:

foreach (var prop in typeof(ConfigFile).GetProperties()) 
{ 
    var attr = prop.GetCustomAttributes(false) 
        .OfType<ConfigFileFieldAttribute>() 
        .FirstOrDefault(); 
    string val; 
    if (attr != null && testDict.TryGetValue(attr.Name, out val)) 
     prop.SetValue(cfgFile, val); 
} 

你甚至可能能夠調用:

var attr = prop.GetCustomAttributes<ConfigFileFieldAttribute>(false).FirstOrDefault(); 

沒有一個IDE對我這麼我現在不能檢查

+0

美麗@Psymunn!完美工作,只需將if(attr!= null && testDict.TryGetValue(attr.Name,val))更改爲if(attr =!null && testDict.TryGetValue(attr.Name,** out ** val))。謝謝! –