Неэфектыўнае код ўнутры геттера?

У мяне ёсць два спісу аднаго і таго ж тыпу, і я хачу, каб мець магчымасць паглядзець спіс абодвух спісаў:

    public List HeaderPages;
    public List SurveyPages;

    public IReadOnlyList AllPages 
    { 
        get 
        {
            List allPages = new List();
            allPages.AddRange(this.HeaderPages);
            allPages.AddRange(this.SurveyPages);
            return allPages;
        } 
    }

Я думаю, што гэта вельмі неэфектыўна, каб стварыць новы спіс аб'ект кожны раз, калі я хачу, каб атрымаць Allpages , так што я думаў, што я мог бы захоўваць прыватны Allpages спіс. Але потым я падумаў, што калі я знаходжуся ў класе, я б памятаць, каб выкарыстоўваць грамадскі AllPages , а не прыватны Allpages - які не можа быць ўдакладнены ,

Любыя элегантныя рашэнні?

10
Вы на самой справе трэба аптымізаваць гэта? Як часта вы тэлефануеце сарбент?
дададзена аўтар rsapru, крыніца
Вы можаце размясціць прыклад некаторага кода, які дэманструе гэтую праблему? Вы просіце, каб мы разгледзелі гіпатэтычны клас, які змяшчае прыватны спіс Allpages і гіпатэтычны метад, які лічыць, што цяжка ўспомніць ці спасылацца Allpages або Allpages ... але гэта цяжка зразумець, гіпатэтычны (неіснуючы) код.
дададзена аўтар ChrisW, крыніца
Я не ведаю, C# дастаткова, каб напісаць адказ, але што, калі кожны раз, калі Командлет Get быў названы захаваны вынік у пераменным экзэмпляры і ўсталяваць нешта накшталт «змянілася = хлусня» Alse як пераменны асобнік. Кожны раз, калі прыбудуць называюцца, калі зменена ілжыва толькі вярнуць кэшаваць спіс. Тады што-небудзь у класе, які змяніў два іншых спісы набораў зменена так.
дададзена аўтар Tom Cooley, крыніца

7 адказы

Калі вы хочаце захаваць два спісу (у адваротным выпадку праверце <�моцны> Hackworth 's адказ), то лепшым рашэннем будзе выкарыстоўваць пашырэння LINQ

public IEnumerable AllPages 
{ 
    get 
    {
        return HeaderPages.Concat(SurveyPages);
    } 
}

This way you do not create any unnecessary collections. It forces you to use IEnumerable though, but in my opinion it is a good thing.

18
дададзена
Дзякуй, мне вельмі падабаецца гэта вельмі чыстае рашэнне і і, безумоўна, паспрабаваць яго на іншых праектах.
дададзена аўтар Tushu, крыніца
+1 Розніца паміж IReadOnlyList і IEnumerable (толькі), што IReadOnlyList таксама падтрымлівае Count і ўласцівасці Index.
дададзена аўтар ChrisW, крыніца

Калі ў вас ёсць кантроль над дызайнам класа старонкі, я хацеў бы дадаць ўласцівасць «BOOL IsHeader» да яго і трымаць адзін публічны спіс усіх аб'ектаў старонкі і дадаць ўсе аб'екты, старонкі ў гэты спіс. Замест таго каб трымаць некалькі іншых спісаў, якія сартуюць свае аб'екты старонкі, вы можаце выконваць пошук па гэтым майстру-спіс, а не для Page аб'ектаў з пэўнымі ўласцівасцямі, пераважна з аператарамі LINQ.

13
дададзена
Я згодны з гэтым, таму што гэта значна больш элегантнае рашэнне, <�я> аднак , калі OP турбуе накладных инстанцировании адзін спіс, а затым робіць O (N) аперацый па ўсіх дадзеных доступы могуць не быць іх каханым , Яны былі б, вядома, няправільна, так як п амаль напэўна трывіяльна.
дададзена аўтар Sebastian, крыніца
У мяне ёсць кантроль над Старонка класа. У рэшце рэшт, я вырашыў, што гэты метад лепш за ўсё падыходзіць для майго праекта.
дададзена аўтар Tushu, крыніца
Я думаю, што гэта сапраўды добры савет.
дададзена аўтар yogman, крыніца
Нават калі ён мае кантроль над Старонка клас, як вы ведаеце, як HeaderPages і SurveyPages ня непусты?
дададзена аўтар abuzittin gillifirca, крыніца
Чаму б не выкарыстоўваць пералік замест Bool ? Гэта дазволіць лягчэй мадыфікаваць ў будучыні, калі больш тыпаў старонак выскачыць?
дададзена аўтар Jeff Vanzella, крыніца
Я хацеў бы зрабіць гэта цалкам без HeaderPages і SurveyPages, што ўвесь сэнс майго адказу.
дададзена аўтар TacB0sS, крыніца

Як вы сказалі, трымаць іншы спіс, які будзе ўтрымліваць ўсе элементы, і пры даданні элемента ў адным з два абнаўлення ўнутранага спісу ... вы маглі б зрабіць спіс прыватным і зрабіць дапаможны метад, якія абнаўляюць галоўны спіс і ўнутраны спіс.

З вашым кодам у любым выпадку вы будзеце ствараць спіс кожны пункт гэта называецца, і я думаю, што гэта можа прывесці да памылак, калі захаваць спасылку sonewhere і вас за выключэннем таго, абнаўляюцца (гэта не будзеце трымаць значэння пры стварэнні) з апошнімі старонкамі ,

Іншы спосаб трымаць Approch але стварыць спіс толькі адзін раз і вярнуць яго. Тады вы павінны знайсці спосаб, каб ведаць, да класа, калі адзін з спісу змяніўся, калі змяніліся абнавіць спіс (выразны і readd, каб пазбегнуць новага асобніка)

Я мог бы дадаць прыклад кода, калі вам трэба.

5
дададзена

Вы можаце выкарыстоўваць ляніва ініцыялізацыю для дасягнення таго ж:

private Lazy> _lazyPageList = new Lazy>(GetPageList);

public IReadOnlyList AllPages
{
    get
    {
        return lazyPageList.Value;
    }
}

private ListGetPageList(){
    List allPages = new List();
    allPages.AddRange(this.HeaderPages);
    allPages.AddRange(this.SurveyPages);
    return allPages;
}
3
дададзена
А што добрага ён будзе рабіць? Вы ўсё роўна прыйдзецца абнаўляць AllPages нейкім чынам пры змене іншых калекцый.
дададзена аўтар yogman, крыніца
ад пытання: «Я мог бы захоўваць асабісты спіс" Allpages ", але потым я падумаў, што калі я знаходжуся ў класе, я б памятаць, каб выкарыстоўваць грамадскі" Allpages ", а не прыватны" Allpages "- <�я>, які не можа быць ўдакладненых «. Уводзячы Гультай ўласцівасць не вырашае гэтую праблему, гэта толькі дадае дадатковую складанасць кода. (Вы ўсё яшчэ стварыць дадатковае поле _lazyPageList )
дададзена аўтар yogman, крыніца
LINQ не стварае новы спіс. Гэта стварае новую нумарацыю логіку над існуючай калекцыяй (-s). Каб стварыць новы спіс, вы павінны выклікаць ToList() метад.
дададзена аўтар yogman, крыніца
Тое, што я зразумеў з першапачатковага пытання спісы не мяняюцца. Ідэя заключаецца ў тым, каб пазбегнуць стварэння новага спісу кожны раз AllPages ўласцівасць даступна. @chazjn не хоча, каб стварыць зменную-член для захоўвання выніку. Лянівы клас лепш за ўсё падыходзіць для гэтага.
дададзена аўтар Sandeep, крыніца
Я згодны з вамі, што новыя змены не будуць абнаўляцца з адкладзенай. Аднак вы выкарыстоўваць пашырэнне Linq або код у зыходным паведамленні новага спіс будзе створаны кожны раз, калі ўласцівасць доступу. Лепш было б захаваць вынік temporarilty зменных і абнаўляць яго, толькі калі альбо з спісу змяніўся
дададзена аўтар Sandeep, крыніца

Вы прафіляваны код і вызначыў, што гэты выклік з'яўляецца праблемай? Калі няма, то, што перад аптымізацыяй нічога.

Існуе агульнае рашэнне праблем, як гэта, што выкарыстоўваць смецце сцяг для адсочвання, ці з'яўляецца вяртаецца значэнне. Для гэтага вам трэба будзе абгарнуць ўсе выпадкі, калі старонкі загалоўка і апытання могуць быць зменены такім чынам, што парушае спіс Allpages і ёсць гэтыя выклікі ўсталяваць забруджаны сцяг. Затым заменіце паглынальнік з чымсьці накшталт гэтага:

private List allPages;
private boolean dirty;

public IReadOnlyList AllPages 
{ 
    get 
    {
        if (dirty)
        {
           allPages = new List();
           allPages.AddRange(this.HeaderPages);
           allPages.AddRange(this.SurveyPages);
        }
        return allPages;
    } 
}

На жаль, забруджаны сцягі могуць быць схільныя памылак, так крочыць з асцярожнасцю.

2
дададзена
@ChrisW: Дзякуй, Я выправіў гэтую памылку. Я не ведаю, што больш эфектыўна ў C#, вам прыйдзецца час гэта.
дададзена аўтар rsapru, крыніца
Там памылка ў кодзе прыкладу: Allpages імёны лакальнай зменнай і член. Акрамя таго, калі брудныя вы аддаеце перавагу Allpages = новы List (); або allPages.Clear (); ?
дададзена аўтар ChrisW, крыніца
@ChrisW я б сказаў, проста стварыць новы спіс, і хай стары, збірацца. Калі вы спрабуеце зрабіць Ясна, што вам трэба праверыць, калі Allpages ініцыялізуецца першым.
дададзена аўтар rob, крыніца

Дзве альтэрнатывы Хакворта адказ , калі вы не маеце кантроль над класам старонкі:

  • Either, create two subclasses HeaderPage and SurveyPage, bother/either of which you can store in the List AllPages
  • Or, add a Dictionary in which to remember the type of page (the 'type of page' is shown here as a bool, but could be an enum) for each page in your single List AllPages

Доступ да гэтага слоўніку можна вызначыць як метад пашырэння:

static class PageExtensions
{
   //Or this could be a non-static member of your container class and passed
   //as a parameter into the GetPageType and SetPageType extension methods.
    static Dictionary dictionary = new Dictionary();

    public static bool? GetPageType(this Page page)
    {
        bool rc;
        return (dictionary.TryGetValue(page, out rc)) ? rc : null;
    }
    public static void SetPageType(this Page page, bool type)
    {
        dictionary[page] = type;
    }
}
1
дададзена
Я сказаў, «можа быць пералік» ў адказ. У якасці альтэрнатывы перайменаваць звязаныя з імі метады пашырэнняў, напрыклад, у SetIsHeader замест SetPageType.
дададзена аўтар ChrisW, крыніца
Bool нічога не азначае ў гэтым кантэксце. Я хацеў бы змяніць яго на пералік , што імёны тыпу старонкі.
дададзена аўтар Jeff Vanzella, крыніца

Што людзі збіраюцца хацець рабіць з Allpages , і яны будуць мець якія-небудзь чакання аб тым, як ён павінен паводзіць сябе, калі ніжэйлеглых змены дадзеных?

Калі намер складаецца ў тым, што код, які чытае AllPages не збіраецца выкарыстоўваць яго пасля таго, як нешта зменіцца ў наступны раз, вы маглі б мець кожны асобнік вашай уласнай асобы стварыць (ці ляніва ствараць) экзэмпляр AllPageWrapper , які змяшчае спасылку на яго стваральніка разам з «падліку» змяненне і, магчыма, колькасць элементаў у HeaderPages . Метады і ўласцівасці AllPageWrapper забяспечыць абгорнуты аб'ект не быў зменены, і затым выкарыстаць гэтае месца, абгорнуты ў якасці крыніцы дадзеных. Праіндэксаваны геттер можа выглядаць прыкладна так:

public Page this(int index)
{ get
  {
    if (changeCount != parent.changeCount)
      throw InvalidOPerationException(...);
    if (index > headerCount)
      return parent.SurveyPages(index-headerCount);
    else
      return parent.HeaderPages(index);
  }
}

Такі падыход дазволіў бы AllPages ўласцівасць проста вяртае аб'ект-абалонкі, без неабходнасці рабіць якую-небудзь рэальную «працу». Код, які мае патрэбу ў отдельностоящий копію спісу можна выкарыстоўваць выкарыстоўваць thing.AllPages.ToList() , але код, які трэба толькі коратка не трэба турбавацца.

0
дададзена