如何使这种方法更通用?

时间:2010-08-26 17:34:07

标签: c#

我有这个名为LoadToDictionary的方法。它接受字典和文件路径。目前,它看起来像这样: void LoadToDictionary(Dictionary<string, string> dict, string filePath。然后在里面,它会有很多代码将filePath中文件的内容提取到字典中。我想让它更通用,所以它可以,比如说,用一个带有int的字典,以及改变方法中的解析代码的能力。我应该标记此方法,然后覆盖它吗?还有其他办法吗?

2 个答案:

答案 0 :(得分:36)

过早的普遍性使得过早的优化成为金钱的根源。 通用性很高,昂贵的代码应该通过明确的好处来证明。

因此,我会在特定场景的基础上提高您的方法的通用性。我可以想出许多方法来使你的方法更通用:

  1. 不要把字符串字典串起来;把字符串比作任意类型。

  2. 不要带Dictionary<...>;采取IDictionary<...>

  3. 不要拿任何字典。取一个Action<K, V>,其行动可能是在字典中输入该项目。

  4. 不要使用文件名。无论如何,您只是将文件名转换为流,因此请先开始使用Stream。让呼叫者为您打开流。

  5. 不要带流。无论如何,您只是将流转换为一系列项目,因此请使用IEnumerable<...>并让调用者为您解析流。

  6. 我们能做到这一般吗?假设我们有一个T序列,然后将其转换为从K到V的映射。我们需要什么?序列,键提取器,值提取器和地图编写器:

    static void MakeMap<T, K, V>(this IEnumerable<T> sequence, Action<K, V> mapWriter, Func<T, K> keyExtractor, Func<T, V> valueExtractor)
    {
        foreach(var item in sequence)
            mapWriter(keyExtractor(item), valueExtractor(item));
    }
    

    注意代码如何变得非常简短。这是非常奇怪的一般,因此呼叫网站现在看起来像一个邪恶的混乱。这真的是你想要的吗? 您是否会有效地使用所有这些通用性?可能不是。 您实际拥有哪些方案可以促使您更加普遍?使用这些特定方案来激发您的重构。

    这是我们能走的吗?我们能比这更普遍吗?当然。例如,我们可以注意到在那里产生副作用似乎很糟糕。该方法不应该只返回一个新构造的字典吗?该词典的比较政策应该是什么?如果有多个项目具有相同的密钥怎么办?它应该被替换,还是应该让字典实际上是从键到值列表的映射?我们可以采取这些想法并制定一种解决所有这些问题的新方法:

    public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    Func<TSource, TElement> elementSelector,
    IEqualityComparer<TKey> comparer) { ... }
    

    嘿,我们刚刚彻底改造了ToLookup()扩展方法。有时,当你使方法足够通用时,你会发现它已经存在。

答案 1 :(得分:1)

我在这里看到两个实际问题:
1)方法签名可以是动态的,以便它所期望的类型可以改变吗?
2)方法体可以是动态的,这样我的逻辑就可以在运行中改变。

我不确定如何这两个中的任何一个都可以通过使用Reflection和相当多的代码来完成。不过,我确信这里有人。

根据您的需要,基本方法重载听起来就像您实际需要的那样。

使用您的示例:

void LoadToDictionary(Dictionary<string, string> dict, string filePath)
{ ... code here ... }

//to have a LoadToDictionary method which accepts Dictionary<int, int>
void LoadToDictionary(Dictionary<int, int> dict, string filePath)

//To change the processing logic, you either need a new method name, 
// or to override the original in an inheriting class

void AlternateLoadToDictionary(Dictionary<string, string> dict, string filePath)
override void LoadToDictionary(Dictionary<string, string> dict, string filePath)

更好的选择是将解析逻辑与Dictionary创建逻辑分开。您甚至可以从LoadDictionary方法中调用其他方法,这样正常的重载也可以在那里工作

void LoadToDictionary(Dictionary<string, string> dict, string filePath)
{
    string[] fileLines;

    if([yourBaseLineCondition])
    fileLines = LoadDataFromFile(filePath, false);

    else fileLines = LoadDataFromFile(filePath, true); 
}

string[] LoadDataFromFile(string filePath, bool altLogic)
{
    if(altLogic) return LoadDataFromFileAlt(filePath)
    else
    { ... your logic ... }
}

string[] LoadDataFromFileAlt(string filePath)
{ ... your alt logic... }

基本方法重载为您提供了很多灵活性。更重要的是,它允许您遵循YAGNI原则而不会切断扩展途径。如果需要,您可以随时返回代码并添加LoadToDictionary<myCustomObject, myCustomObject>方法。