如何重构配置文件中高度重复的读取部分
本文关键字:高度 读取部 配置文件 何重构 重构 | 更新日期: 2023-09-27 18:01:58
我需要将配置文件的多个部分转换为字典。这些字典的值具有不同的类型。下面两个类可以工作,但它们几乎相同:
public class IntConfigSection
{
private static readonly ILog Log = LogManager.GetLogger(typeof(IntConfigSection));
public static Dictionary<String, int> LoadSection(string sectionName)
{
var ret = new Dictionary<String, int>();
try
{
var offsetsHash = (Hashtable)ConfigurationManager.GetSection(sectionName);
foreach (DictionaryEntry entry in offsetsHash)
{
ret.Add((String)entry.Key, int.Parse((String)entry.Value));
}
}
catch(Exception e)
{
Log.ErrorFormat("LoadSection:" + e);
}
return ret;
}
}
public class StringConfigSection
{
private static readonly ILog Log = LogManager.GetLogger(typeof(StringConfigSection));
public static Dictionary<String, String> LoadSection(string sectionName)
{
var ret = new Dictionary<String, String>();
try
{
var offsetsHash = (Hashtable)ConfigurationManager.GetSection(sectionName);
foreach (DictionaryEntry entry in offsetsHash)
{
ret.Add((String)entry.Key, (String)entry.Value);
}
}
catch (Exception e)
{
Log.ErrorFormat("LoadSection:" + e);
}
return ret;
}
}
下面的代码不能按要求工作,但它演示了我要完成的任务:
public class ConfigSection<T>
{
private static readonly ILog Log = LogManager.GetLogger(typeof(StringConfigSection));
public static Dictionary<String, T> LoadSection(string sectionName)
{
var ret = new Dictionary<String, T>();
try
{
var offsetsHash = (Hashtable)ConfigurationManager.GetSection(sectionName);
foreach (DictionaryEntry entry in offsetsHash)
{
//builds but does not always do what I want
ret.Add((String)entry.Key, (T)entry.Value);
// does not compile
//ret.Add((String)entry.Key, T.Parse((String)entry.Value));
}
}
catch (Exception e)
{
Log.ErrorFormat("LoadSection:" + e);
}
return ret;
}
}
编辑:我的最终版本如下:
public class ConfigSectionLoader
{
public static Dictionary<String, int> LoadIntSection(string sectionName)
{
return ConfigSection<int>.LoadSection(sectionName, int.Parse);
}
public static Dictionary<String, String> LoadStringSection(string sectionName)
{
return ConfigSection<String>.LoadSection(sectionName, val => val);
}
}
internal class ConfigSection<T>
{
private static readonly ILog Log = LogManager.GetLogger(typeof(StringConfigSection));
internal static Dictionary<String, T> LoadSection(string sectionName, Func<String, T> parseFunc)
{
var ret = new Dictionary<String, T>();
try
{
var hash = (Hashtable)ConfigurationManager.GetSection(sectionName);
foreach (DictionaryEntry entry in hash)
{
ret.Add((String)entry.Key, parseFunc((String)entry.Value));
}
}
catch (Exception e)
{
Log.ErrorFormat("LoadSection:" + e);
}
return ret;
}
}
我唯一关心的是:val => val是什么都不做的最简单的lambda吗?
我的建议如下:
public abstract class ConfigSectionBase<T>
{
public static Dictionary<String, T> LoadSection(string sectionName)
{
...
//builds but does not always do what I want
ret.Add((String)entry.Key, Convert((string)entry.Value));
...
}
abstract T Convert(string v);
}
public class IntConfigSection: ConfigSectionBase<int>
{
override int Convert(string v)
{
return int.Parse(v);
}
}
public class StringConfigSection: ConfigSectionBase<string>
{
override string Convert(string v)
{
return v;
}
}
(免责声明:我没有尝试代码!)
编辑:
通过使用Convert.ChangeType
:
Convert
函数。public abstract class ConfigSection<T>
{
public static Dictionary<String, T> LoadSection(string sectionName)
{
...
//builds but does not always do what I want
ret.Add((String)entry.Key,
(T)Convert.ChangeType((string)entry.Value, typeof(T)));
...
}
}
您可以传入一个实际对该类型进行解析的函数:(注意:未测试的代码,将其视为一个想法而不是工作代码:D)
public class ConfigSection<T>
{
private static readonly ILog Log = LogManager.GetLogger(typeof(StringConfigSection));
public static Dictionary<String, T> LoadSection(string sectionName, Func<String,T> parseFunc)
{
var ret = new Dictionary<String, T>();
try
{
var offsetsHash = (Hashtable)ConfigurationManager.GetSection(sectionName);
foreach (DictionaryEntry entry in offsetsHash)
{
ret.Add((String)entry.Key, parseFunc((String)entry.Value));
}
}
catch (Exception e)
{
Log.ErrorFormat("LoadSection:" + e);
}
return ret;
}
}
,然后作为lambda(或类似的..)传入实际的解析器
或者你可以在类的构造函数中包含解析器,然后让它成为一个成员,这样你就不必每次都传递它了。
public class ConfigSection<T>
{
private Func<String, T> myParseFunc = null;
public ConfigSection<T>(Func<String,T> parParseFunc)
{
myParseFunc = parParseFunc;
}
private static readonly ILog Log = LogManager.GetLogger(typeof(StringConfigSection));
public static Dictionary<String, T> LoadSection(string sectionName)
{
var ret = new Dictionary<String, T>();
try
{
var offsetsHash = (Hashtable)ConfigurationManager.GetSection(sectionName);
foreach (DictionaryEntry entry in offsetsHash)
{
ret.Add((String)entry.Key, myParseFunc((String)entry.Value));
}
}
catch (Exception e)
{
Log.ErrorFormat("LoadSection:" + e);
}
return ret;
}
}
你可以这样命名它
ConfigSection<int> = new ConfigSection<int>(int.Parse);
这是一个常见的问题,您总是以某种程度的重复结束。关键是要弄清楚复制的大小以及本地化的位置。在这个特定的示例中,您可以:
- 传递一个
Func<string, T>
parsemmethod参数到你的泛型类构造函数。这允许你支持任何类型,甚至允许同一类型以不同的方式解析不同的配置节实例。 - 获取类型的TypeConverter,并尝试从字符串转换。
- 要求类型支持IConvertible,并且可以从string中转换。
- 使用反射来查找类型上的静态Parse或TryParse方法。这并不理想,但是BCL有使用类似的"魔法方法名"的例子。