2010-08-26 5 views
3

У меня есть этот метод под названием LoadToDictionary. Он принимает словарь и путь к файлу. В настоящее время он будет выглядеть примерно так: void LoadToDictionary(Dictionary<string, string> dict, string filePath. Затем внутри, у него будет много кода для извлечения содержимого файла в filePath в словарь. Я хочу сделать его более общим, чтобы он мог, скажем, взять словарь с помощью int вместо него и возможность изменить код разбора в методе. Должен ли я отмечать этот метод, а затем переопределять его? Есть ли другой путь?Как я могу сделать этот метод более общим?

+0

Пожалуйста, добавьте код, чтобы мы лучше поняли, что можно улучшить ... –

ответ

36

Преждевременная общность дает преждевременную оптимизацию работы за деньги как корень зла. Общность дорого стоит, а дорогостоящий код должен быть оправдан благодаря явным преимуществам.

Я бы поэтому увеличил общность в вашем методе на основе конкретных сценариев. Я могу думать о многих способах сделать ваш метод более общим:

  1. Не принимать словарь строки в строку; возьмите словарь, скажем, строки произвольного типа.

  2. Не принимайте адрес Dictionary<...>; возьмите IDictionary<...>.

  3. Не используйте словарь. Возьмите Action<K, V>, чье действие может заключаться в том, чтобы ввести элемент в словаре.

  4. Не принимайте имя файла. В любом случае вы просто превратите имя файла в поток, поэтому сначала начните поток. Попросите абонента открыть поток для вас.

  5. Не принимайте поток. Вы все равно собираетесь превратить поток в последовательность элементов, поэтому возьмите IEnumerable<...> и попросите собеседника проанализировать поток для вас.

Как мы можем это сделать? Предположим, что мы имеем последовательность 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() расширения. Иногда, когда вы делаете достаточно общий метод, вы обнаруживаете, что он уже существует.

+0

Должен сказать, что вы правы. Здесь вы дали очень хорошие идеи. Я, вероятно, передумаю кое-что из этого. – DMan

+3

+1 от меня за * удивительный * ответ. Мое единственное дополнение (чисто мнение) было бы в том, что если у вас есть фрагмент кода, который вы можете сделать более общим и повторно использовать, вы можете упростить свой код, имея пару «сквозных» методов, которые называют это, которые предоставляют подробно, например, тот факт, что он работает на 'IDictionary ', поэтому ваш код вызова не станет феноменально сложным, как упомянул Эрик. – Rob

+1

Удивительный ответ. Я абсолютно согласен. Это принцип YAGNI в действии. –

1

Я вижу два актуальных вопроса здесь:
1) Может ли подписи метода быть динамичной, чтобы типы, которые она ожидает, могут измениться?
2) Может ли тело метода быть динамичным, так что моя логика может меняться «на лету».

Я не уверен , как любой из этих двух может быть выполнен с использованием Reflection и справедливого количества кода gen. Я уверен, что есть те, кто есть.

В зависимости от того, что вам нужно, базовый метод перегрузки звучит так, как будто вы действительно ищете.

Используя ваш пример:

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) 

Еще лучшей альтернативой является иметь свой синтаксический анализ логики отдельно от вашего словаря логики создания. Вы даже можете вызвать другой метод внутри вашей 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... } 

Основной метод перегрузка дает много flexability. Что еще более важно, это позволяет вам следовать принципу YAGNI, не сокращая возможности расширения. Вы всегда можете вернуться в свой код и добавить метод LoadToDictionary<myCustomObject, myCustomObject>, если вам нужно это сделать.

Смежные вопросы