Любое преимущество для объекта. GetGetObject (i) над объектами [i]?

StackOverflow https://stackoverflow.com/questions/3159045

Вопрос

Я рефакторирую немного кода доступа к данным C # от предыдущего разработчика и любопытен в рисунке, который он использовал.

Код изначально открыл коллекции (массивы) различных объектов бизнес-объектов в стиле ActiveRecord - по существу объектов, упаковочные поля базы данных. Я изменяю массивы в общие списки, но аспект кода мне интересно, состоит в том, что предыдущий разработчик получил методы для каждого типа объекта, который он упаковал, таким образом:

public Thing GetThing(int i) {
    return things[i];
}

Есть несколько из этих методов, и я не могу за жизнь меня думать о любых возможных преимуществах использования этого механизма, просто имея в виду вещи [I] напрямую. Предположим, для аргументации ради аргументов, что все является общественным имуществом, а не публичное поле (в этом случае это на самом деле, это фактически реализованное свойство, так что предположение на самом деле верно).

Я упускаю что-то очевидное? Или даже что-то эзотерическое?

ОБНОВИТЬВероятно, я должен уточнить, что эти коллекции в настоящее время доступны изнутри петлей:

for (int i = 0; i < thingsCount; i== ) {
    dosomthing( GetThing(i) );
    dosomethingelse( GetThing(i) );
}

Что я рефакторинг:

for (int i = 0; i < thingsCount; i== ) {
    Thing thing = things[i];
    dosomthing( thing );
    dosomethingelse( thing );
}

И, возможно, даже использовать вещи .Foreach ().

Это было полезно?

Решение

Я не знаю, очевидно ли это, но я думаю, что ты что-то не хватает.

Давайте скажем things является IList<Thing>. Отказ Затем разоблачить его напрямую (как Things) позволил бы позвонить коду звонить Add, Insert, RemoveAt, и т. Д. Может быть, предыдущий разработчик не хотел этого разрешать (и я уверен, что есть много веских причин для этого).

Даже предположить, что это Thing[] (так Add, и т. Д. Не будет доступен), подвергая бы его как таковое все равно позволит вызове кода сделать что-то вроде obj.Things[0] = new Thing(); Это может быть операция, которая не должна быть разрешена в зависимости от реализации класса.

Ты мог разоблачать Things как ReadOnlyCollection<Thing> что бы позаботиться о большинстве этих проблем. Но то, что это сводится к этому: если разработчик Только хочет позволить призванию к коду доступа к элементам по индексу - ничего более - тогда предоставляя один GetThing Метод, как средство для этого, честно, честно, делает безусловно самым смыслом.

Теперь, предоставлено, есть также этот вариант: реализация this[int] недвижимость только с get Accessor. Но это имеет смысл, только если рассматриваемый класс, по сути, является коллекцией Thing Объекты исключительно (то есть нет также коллекция некоторых разное Тип объекта, который вы хотите предоставить доступ в классе).

Все сказали, я думаю, что GetThing Подход довольно звук.

То, что сказал, с того, как вы сформулировали ваш вопрос, он звучит так, как предыдущий разработчик сделал несколько других симпатичных решений:

  1. Если он / она также открытый things Коллекция непосредственно как государственная собственность, ну тогда ... это поражает все цели GetThing Метод, не так ли? Результатом является просто раздутый интерфейс (я, как правило, думаю, что это не отличный знак, когда у вас есть несколько методов для достижения точно такого же, если они не доказаны не документированными как псевдонимы для некоторой оправданной причины). [Обновлять: Кажется, что предыдущий разработчик сделал нет сделай это. Хорошо.
  2. Похоже, предыдущий разработчик тоже был внутренне Доступ к предметам things с использованием GetThing Метод, который просто глупо (на мой взгляд). Зачем представить бессмысленные накладные расходы на дополнительный метод, используя общедоступный интерфейс класса из самого класса? Если вы в классе, вы уже внутри реализации И может получить доступ к частным / защищенным данным, все, что вы хотите - не нужно притворяться иным.

Другие советы

Вы, вероятно, хотите разоблачить объект как IList<Thing>. Отказ Это даст вам возможности индексации, которые вы ищете, но также получаете ассортимент функций LINQ, такие как создание нового списка элементов на основе условий. Плюс IList<T> внедрение IEnumerable<T> так что вы сможете использовать foreach в петлю через объекты.

Например, в вашем классе:

public IList<Thing> Things { get; private set; }

например, использование:

Thing x = business.Things[3];

или

var x = business.Things.Where(t => t.Name == "cori");

Здесь есть две вещи, чтобы отметить здесь. Во-первых, вы хотите сохранить переменные объекты частным и использовать GetTers и Getters для доступа к ним. Это предотвращает случайное изменение или изменение переменных объектов.

Во-вторых, он считается хорошим конвенцией именования, где термины Get / Set должны использоваться, когда атрибут обращается напрямую. Это помогает повысить читаемость.

Хотя это государственная собственность в этом случае, использование Getbers и Setters повышают читаемость и помогает предотвращает неожиданное поведение. Неважно, если вы получаете доступ к переменным объекта внутри цикла, вы должны продолжать использовать GetThing соглашение.

Наконец, если вы получаете доступ к переменным из объекта, вам не нужно использовать Gotter или Setter.

Примечание. В целом считается хорошим стилем, чтобы поддерживать объектные переменные частные и использовать GetTers / Setters для всех языков

Руководящие принципы стиля C ++

C # Руководство по стилю

Вы также можете быть заинтересованы в вопросе »Getter и Setter для класса в классе C #"

Если бы я должен был догадаться, я бы сказал, что этот разработчик использовался для некоторого другого языка, такого как Java, и не был полностью осведомлен о стандартной практике в C #. Номенклатура «Get [Property]» очень сильно используется в Java, JavaScript и т. Д. C # заменяет это свойствами и индексаторами. Свойства каждый так же мощный, как Getter и Benters, но легче писать и использовать. Единственный раз, когда вы обычно видите «получаете [что-то] в C #, если:

  • Операция, скорее всего, будет достаточно дорогой, чтобы вы действительно хотели ездить домой, что это не просто простой доступ к членам (например, GetPrimeNumbers()), или
  • Ваша коллекция на самом деле включает в себя несколько индексированных коллекций. (например GetRow(int i) а также GetColumn(int i)). Отказ Даже в этом случае более распространено просто разоблачить каждую из этих проиндексированных коллекций в качестве недвижимости к самому себе, что имеет индексированный тип (»table.Rows[2]").

Если ты Только Доступ к этим значениям в for петли, коллекция должна реализовать IEnumerable<Thing>, что даст вам доступ к методам LINQ и foreach построить. Если вам все еще нужно иметь проиндексированные получатели, вы должны рассмотреть возможность использования собственного интерфейса, который расширяется IEnumerable<T>, но дополнительно предоставляет:

T this[int i] { get; }

Таким образом, вы не даете потребителям впечатление, что они могут Add а также Remove Объекты в этой коллекции.

Обновлять

Я знаю, что это в основном вопрос стиля, который подлежит дебатам, но я действительно думаю, что GetThings Решение не является правильным способом делать вещи. Следующая стратегия, в то время как требуется немного больше работы, гораздо больше в соответствии с тем, как разработаны стандартные классы и каркасы .NET:

public class ThingHolderDataAccess
{
    public ThingHolder GetThingHolderForSomeArgs(int arg1, int arg2)
    {
        var oneThings = GetOneThings(arg1);
        var otherThings = GetOtherThings(arg2);
        return new ThingHolder(oneThings, otherThings);
    }
    private IEnumerable<OneThing> GetOneThings(int arg)
    {
        //...
        return new List<OneThing>();
    }
    private IEnumerable<AnotherThing> GetOtherThings(int arg2)
    {
        //...
        return new List<AnotherThing>();
    }
}

public class ThingHolder
{
    public IIndexedReadonlyCollection<OneThing> OneThings
    {
        get;
        private set;
    }

    public IIndexedReadonlyCollection<AnotherThing> OtherThings
    {
        get;
        private set;
    }

    public ThingHolder(IEnumerable<OneThing> oneThings,
                       IEnumerable<AnotherThing> otherThings)
    {
        OneThings = oneThings.ToIndexedReadOnlyCollection();
        OtherThings = otherThings.ToIndexedReadOnlyCollection();
    }
}

#region These classes can be written once, and used everywhere
public class IndexedCollection<T> 
    : List<T>, IIndexedReadonlyCollection<T>
{
    public IndexedCollection(IEnumerable<T> items)
        : base(items)
    {
    }
}

public static class EnumerableExtensions
{
    public static IIndexedReadonlyCollection<T> ToIndexedReadOnlyCollection<T>(
        this IEnumerable<T> items)
    {
        return new IndexedCollection<T>(items);
    }
}

public interface IIndexedReadonlyCollection<out T> : IEnumerable<T>
{
    T this[int i] { get; }
}
#endregion

Используя код выше, может выглядеть что-то подобное:

var things = _thingHolderDataAccess.GetThingHolderForSomeArgs(a, b);
foreach (var oneThing in things.OneThings)
{
    // do something
}
foreach (var anotherThing in things.OtherThings)
{
    // do something else
}

var specialThing = things.OneThings[c];
// do something to special thing

Как указали другие ответы, это проблема ограничения доступа к самому массиву (или списку).

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top