Использует.NET 4.0 Кортежа в моем Коде C# Плохое Проектное решение?

С добавлением класса Кортежа в .net 4 я пытался решить, если использование их в моем дизайне является плохим выбором или нет. Путем я вижу его, Кортеж может быть ярлыком на запись класса результата (я уверен, что существует другое использование также).

Так это:

public class ResultType
{
    public string StringValue { get; set; }
    public int IntValue { get; set; }
}

public ResultType GetAClassedValue()
{
    //..Do Some Stuff
    ResultType result = new ResultType { StringValue = "A String", IntValue = 2 };
    return result;
}

Эквивалентно этому:

public Tuple GetATupledValue()
{
    //...Do Some stuff
    Tuple result = new Tuple("A String", 2);
    return result;
}

Так откладывание возможности, что я упускаю суть Кортежей, является примером с Кортежем плохое проектное решение? Мне это походит на меньшую помеху, но не как сам документирование и чистый. Значение этого с типом ResultType, очень ясно позже, что каждая часть средств класса, но у Вас есть дополнительный код для поддержания. С Tuple необходимо будет искать и выяснить что каждый Item представляет, но Вы пишете и поддерживаете меньше кода.

Любой опыт, который Вы имели с этим выбором, значительно ценился бы.

166
задан chiccodoro 13 November 2014 в 11:30
поделиться

9 ответов

Кортежи великолепны, если вы контролируете их создание и использование - вы можете поддерживать контекст, который важен для их понимания.

Однако в общедоступном API они менее эффективны. Потребитель (а не вы) должен либо угадывать, либо искать документацию, особенно для таких вещей, как Tuple .

Я бы использовал их для частных / внутренних членов, но использовал бы классы результатов для общедоступных / защищенных членов.

Этот ответ также содержит некоторую информацию.

162
ответ дан 23 November 2019 в 21:04
поделиться

Кортежи - бесполезная фреймворк в .NET 4. Я думаю, что в C # 4.0 была упущена прекрасная возможность. Мне бы хотелось иметь кортежи с именованными членами, чтобы вы могли обращаться к различным полям кортежа по имени вместо Value1 , Value2 и т. Д.

Это было бы потребовалось изменить язык (синтаксис), но это было бы очень полезно.

1
ответ дан 23 November 2019 в 21:04
поделиться

Использование класса типа ResultType более наглядно. Вы можете дать значимые имена полям в классе (тогда как с кортежем они будут называться Item1 и Item2 ). Это даже более важно, если типы двух полей одинаковы: имя четко различает их.

5
ответ дан 23 November 2019 в 21:04
поделиться

Подобно ключевому слову var , оно предназначено для удобства, но им легко злоупотребить.

По моему скромному мнению, не выставляйте Tuple как возвращаемый класс. Используйте его в частном порядке, если этого требует структура данных службы или компонента, но возвращайте хорошо сформированные хорошо известные классы из общедоступных методов.

// one possible use of tuple within a private context. would never
// return an opaque non-descript instance as a result, but useful
// when scope is known [ie private] and implementation intimacy is
// expected
public class WorkflowHost
{
    // a map of uri's to a workflow service definition 
    // and workflow service instance. By convention, first
    // element of tuple is definition, second element is
    // instance
    private Dictionary<Uri, Tuple<WorkflowService, WorkflowServiceHost>> _map = 
        new Dictionary<Uri, Tuple<WorkflowService, WorkflowServiceHost>> ();
}
8
ответ дан 23 November 2019 в 21:04
поделиться

Это зависит, конечно! Как вы сказали, кортеж может сэкономить код и время, когда вы хотите сгруппировать некоторые элементы для местного потребления. Вы также можете использовать их для создания более общих алгоритмов обработки, чем если бы вы передавали конкретный класс. Я не могу вспомнить, сколько раз мне хотелось иметь что-то помимо KeyValuePair или DataRow, чтобы быстро передать некоторую дату из одного метода в другой.

С другой стороны, вполне возможно переусердствовать и передавать кортежи, где вы можете только догадываться, что они содержат. Если вы собираетесь использовать кортеж для разных классов, возможно, было бы лучше создать один конкретный класс.

Конечно, при модерации кортежи могут привести к более лаконичному и удобочитаемому коду. Вы можете посмотреть на C ++, STL и Boost примеры того, как кортежи используются в других языках, но, в конце концов, нам всем придется поэкспериментировать, чтобы найти, как они лучше всего подходят для среды .NET.

2
ответ дан 23 November 2019 в 21:04
поделиться

Кортежи - довольно неприятное дополнение к CLR с точки зрения программиста на C #. Если у вас есть коллекция элементов разной длины, вам не нужно, чтобы они имели уникальные статические имена во время компиляции.

Но если у вас есть коллекция постоянной длины, это означает, что каждое фиксированное местоположение в коллекции имеет определенное предопределенное значение. И в этом случае всегда лучше давать им соответствующие статические имена, чем запоминать значение Item1 , Item2 и т. Д.

Анонимные классы в C # уже предоставляют превосходное решение для наиболее распространенного частного использования кортежей, и они дают значимые имена элементам, так что они действительно лучше в этом смысле. Единственная проблема в том, что они не могут просочиться из именованных методов. Я бы предпочел снять это ограничение (возможно, только для частных методов), чем иметь конкретную поддержку кортежей в C #:

private var GetDesserts()
{
    return _icecreams.Select(
        i => new { icecream = i, topping = new Topping(i) }
    );
}

public void Eat()
{
    foreach (var dessert in GetDesserts())
    {
        dessert.icecream.AddTopping(dessert.topping);
        dessert.Eat();
    }
}
9
ответ дан 23 November 2019 в 21:04
поделиться

Кортежи могут быть полезны ... но позже они могут стать болью. Если у вас есть метод, который возвращает Tuple , как узнать, что это за значения позже. Были ли они ID, Имя, Фамилия, Возраст или были UnitNumber, Street, City, ZipCode .

18
ответ дан 23 November 2019 в 21:04
поделиться

Как насчет использования кортежей в шаблоне «декорировать-сортировать-убирать украшения»? (Преобразование Шварца для людей, живущих на Perl). Вот надуманный пример, конечно, но кортежи кажутся хорошим способом справиться с такими вещами:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] files = Directory.GetFiles("C:\\Windows")
                    .Select(x => new Tuple<string, string>(x, FirstLine(x)))
                    .OrderBy(x => x.Item2)
                    .Select(x => x.Item1).ToArray();
        }
        static string FirstLine(string path)
        {
            using (TextReader tr = new StreamReader(
                        File.Open(path, FileMode.Open)))
            {
                return tr.ReadLine();
            }
        }
    }
}

Теперь я мог бы использовать Object [] из двух элементов или в этом конкретном примере строку [] of два элемента. Дело в том, что я мог бы использовать что угодно в качестве второго элемента в кортеже, который используется внутри и довольно легко читается.

5
ответ дан 23 November 2019 в 21:04
поделиться

На мой взгляд, Tuple - это ярлык для записи класса результата (I уверен, что есть и другие варианты использования).

Есть и другие полезные применения для Tuple <> - большинство из них включает абстрагирование семантики определенной группы типов, имеющих схожую структуру, и рассмотрение их просто как упорядоченного набора значений. Во всех случаях преимущество кортежей состоит в том, что они избегают загромождения вашего пространства имен классами только для данных, которые предоставляют свойства, но не методы.

Вот пример разумного использования Tuple <> :

var opponents = new Tuple<Player,Player>( playerBob, playerSam );

В приведенном выше примере мы хотим представить пару противников, кортеж является удобным способом объединения этих экземпляров в пары без необходимости создать новый класс.Вот еще один пример:

var pokerHand = Tuple.Create( card1, card2, card3, card4, card5 );

Покерная комбинация может рассматриваться как просто набор карт - и кортеж (может быть) разумный способ выразить эту концепцию.

исключая возможность того, что я мне не хватает точки кортежей, это пример с кортежем плохой дизайн choice?

Возврат строго типизированных экземпляров Tuple <> как части общедоступного API для общедоступного типа редко бывает хорошей идеей. Как вы сами понимаете, кортежи требуют, чтобы участвующие стороны (автор библиотеки, пользователь библиотеки) заранее согласовали цель и интерпретацию используемых типов кортежей. Достаточно сложно создать интуитивно понятные и понятные API-интерфейсы, а публичное использование Tuple <> только скрывает назначение и поведение API.

Анонимные типы также являются разновидностью кортежей , однако они строго типизированы и позволяют указывать понятные, информативные имена для свойств, принадлежащих типу. Но анонимные типы сложно использовать в разных методах - они были в основном добавлены для поддержки таких технологий, как LINQ, где проекции создавали типы, которым мы обычно не хотели бы присваивать имена. (Да, я знаю, что анонимные типы с одинаковыми типами и именованными свойствами объединяются компилятором).

Мое практическое правило: если вы вернете его из своего общедоступного интерфейса - сделайте его именованным типом .

Другое мое практическое правило использования кортежей: назовите аргументы метода и переменные localc типа Tuple <> как можно более четко - пусть имя отражает значение отношений между элементами кортеж.Подумайте о моем примере var оппонентов = ... .

Вот пример реального случая, когда я использовал Tuple <> , чтобы избежать объявления типа только данных для использования только в моей собственной сборке . Ситуация связана с тем, что при использовании универсальных словарей, содержащих анонимные типы, становится трудно использовать метод TryGetValue () для поиска элементов в словаре, поскольку для этого метода требуется параметр out , который нельзя назвать:

public static class DictionaryExt 
{
    // helper method that allows compiler to provide type inference
    // when attempting to locate optionally existent items in a dictionary
    public static Tuple<TValue,bool> Find<TKey,TValue>( 
        this IDictionary<TKey,TValue> dict, TKey keyToFind ) 
    {
        TValue foundValue = default(TValue);
        bool wasFound = dict.TryGetValue( keyToFind, out foundValue );
        return Tuple.Create( foundValue, wasFound );
    }
}

public class Program
{
    public static void Main()
    {
        var people = new[] { new { LastName = "Smith", FirstName = "Joe" },
                             new { LastName = "Sanders", FirstName = "Bob" } };

        var peopleDict = people.ToDictionary( d => d.LastName );

        // ??? foundItem <= what type would you put here?
        // peopleDict.TryGetValue( "Smith", out ??? );

        // so instead, we use our Find() extension:
        var result = peopleDict.Find( "Smith" );
        if( result.First )
        {
            Console.WriteLine( result.Second );
        }
    }
}

PS Есть еще один (более простой) способ обойти проблемы, возникающие из-за анонимных типов в словарях, и это использование ключевого слова var , чтобы компилятор мог «вывести» тип за вас. Вот эта версия:

var foundItem = peopleDict.FirstOrDefault().Value;
if( peopleDict.TryGetValue( "Smith", out foundItem ) )
{
   // use foundItem...
}
79
ответ дан 23 November 2019 в 21:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: