C# a přístup k parametru delegáta

zemla

C# a přístup k parametru delegáta
« kdy: 26. 04. 2019, 22:45:32 »
Dobrý den,

řeším následující problém : máme v API search metody, které mohou vracet x tuctů záznamů, proto máme requesty jako jejich parametry odvozeny od bázové třídy řekněme MultipleRequest, která obsahuje jako property index prvního záznamu následujícím po x-tém záznamu: jakési take + skip.

Protože mám za úkol najít nějaký konkrétní záznam splňující něco a protože takových metod máme x na entou, mám snahu napsat si helper.

Něco takového:

Kód: [Vybrat]
public class PaginationHelper<TR>
{
   public delegate Task<TR> SearchMethodDelegate(MultipleRequest request);

   public static async Task<TR> GetResultFromSearchAsync(SearchMethodDelegate task, Func<TR,bool> checker, int paging = 50)
   {
      ...
      var result = await task.Invoke(new MultipleRequest(take, skip)); // !!!!!!!!!
      ...
   }
}

Take a Skip vypočítávám v cyklu, ve kterém je i Invoke.

Problém mám s tím, že nechci volat Invoke s bázovou třídou MultipleRequest, ale s potomkem.

Ale jak se prosím k tomu potomkovi dostat?


JmJ

  • ****
  • 305
    • Zobrazit profil
Re:C# a přístup k parametru delegáta
« Odpověď #1 kdy: 27. 04. 2019, 07:23:46 »
Dost mozna mi po ranu neco unika, ale prijde mi, ze to vypada na chybnou myslenku. Tomu getResultAsync musis bud predat instanci multi requestu nebo jeho typ, at uz generikou nebo parametrem. Pokud ruzni potomci multi requestu maji krom skip a take dalsi parametry, pak bych cekal, ze si udelas jejich instanci, nakrmis ji parametry, tu instanci pak predas do search async, tam se vyplni parametry skip a take a preda se to hledacimu tasku. Druha moznost je predat typ a ten pak instanciovat s parametry skip a take.

Re:C# a přístup k parametru delegáta
« Odpověď #2 kdy: 27. 04. 2019, 12:44:32 »
Tzn. kdyz to zobecnim, ty potrebujes mit moznost hledat neco konkretniho v datech, ktere zprostredkovava to API. To API bere jako parametr objekt, kde kazdy z nich dedi z MultipleRequest.

To API vsak nema zadnou metodu, ktera by brala ciste MultipleRequest nacez odpovedela by ti obrovskou response obsahujici vsechny mozne potomky. (nastesti ji nema)

Ty potrebujes tedy volat to API s nejakym konkretnim potomkem/potomky tridy MultipleRequest. A ja se ptam: kde ty konkretni potomky tridy MultipleRequest mas specifikovane?

Ja je nikde nevidim.

Pokud ten konkretni potomek ma byt specifikovany tim generikem "TR", coz si nikde nerekl (a to musim ja za tebe nejak predpokladat), tak ty potrebujes mist toho:

task.Invoke(new MultipleRequest(take, skip));

Udelat neco jako:

task.Invoke(new TR(take, skip));

Coz jsem uz strasne dlouho nedelal a zapomel jsem syntax, a v C# nevim jak se to dela (ale samozrejme to jde), takze si to vygoogli. Nezapomen ale udelat neco jako:

public class PaginationHelper<TR extends MultipleRequest>

A tady k tomu mas primo napovedu:

https://stackoverflow.com/questions/11234452/c-sharp-create-object-obj-new-t



A POZOR, tou cestou co ses vydal ti beztak vznikne zbytecne komplikovana sracka  8)
« Poslední změna: 27. 04. 2019, 12:46:13 od prihlaseny_uzivatel »

Re:C# a přístup k parametru delegáta
« Odpověď #3 kdy: 27. 04. 2019, 13:41:51 »
Jo, ty na 99% delas uplnou stupiditu.

Tady jde videt C# v praxi, ma to 100 ruznych featur a programatori s tim pak pisou takovy govna. Proste to umi delegaty a generika bez type erasure, tak proste i ty jelita (obzvlaste) se to vzdycky budou snazit na neco napasovat, ikdyz ta vec jde udelat uplne jednoduse.

To mi pripomelo minuleho tazatele architekta C#-istu, ktery prichazejic z uzavrene M$ platformy, napise hned v 1. vete "nechci nikomu sdelovat sve knowhow" a potom popise narovnavak na ohybak, ktery vymysleli  :D


Proc si proste jednoduse neudelas neco jako:

Kód: [Vybrat]

FooApiHandler {

   private static final int PAGE_SIZE = 50;

   private FooApiConnector fooApiConnector;

   public FooApiHandler(FooApiConnector fooApiConnector) {..}

   public CockableGuy searchForBiggestCock() {
       CockableGuy biggestCockGuy;
       for(int pageNumber = 0; true ; i++) {
           List<CockableGuy> guys = fooApiConnector.listCockableGuys(pageNumber, PAGE_SIZE);
           guys.add(biggestCockGuy);
           
           biggestCockGuy = findBiggestCock(guys);

           if(guys.size() < PAGE_SIZE)
              break;
       }

        return biggestCockGuy;
   }

   private CockableGuy findBiggestCock(List<CockableGuy> gays)

}


Mam ted na projektu nejakych 400000 radku a doted si nejak nemuzu vybavit jedine pouziti generika, mozna tam nejake je, ale... Nerikam, ze to neni uzitecne, ale proste ty veci jdou vetsinou napsat pekne jednoduseji bez nich. Natoz pak abych knucel, ze generika v Jave maji type erasure. Tvl.

To je jeden z antipatternu, snazit se vsechno udelat nejak chytre a na vsechno napasovat nejaky nesmysl.
« Poslední změna: 27. 04. 2019, 13:49:35 od prihlaseny_uzivatel »

Re:C# a přístup k parametru delegáta
« Odpověď #4 kdy: 27. 04. 2019, 13:59:32 »
A jeste jedna vec, proc to delas async? Protoze jestli to tvoje generikum "TR" ma byt tim typem volaneho requestu, tak oprav me jestli se mylim, ale ty budes ten helper volat vzdycky jen s nejakym tim konkretnim typem Requestu. A v tom Requestu mas uz pagination. A volas jen to jedno API. Tak proc tam mas tvl ten async? Tvl ja ti nechci krivdit jo, neznam tvoji stituaci, ale ty tam ten async beztak mas jen proto, ze C# umi async. Tvl doufam ze ty nejsi senior/architekt jako ten predchozi C#-ista co tu byl.

To je proste uplne trefne, kdyz ma neco X featur, tak lidi najdou X^2 zpusobu, jak v tom prasit.


zemla

Re:C# a přístup k parametru delegáta
« Odpověď #5 kdy: 27. 04. 2019, 14:21:03 »
OK, async je v tomto případě zbytečné.

Generikum potřebuju, protože každé API, což jsem zapoměl napsat, že jich máme víc a každý s vlastním odvozeným requestem, vrací pokaždé jinou response.

Mám to jako zjednodušený příklad takto:

Kód: [Vybrat]
public class MultipleRequest
    {
        public MultipleRequest(int take, int skip)
        {
            Take = take;
            Skip = skip;
        }
        public int Take { get; set; }
        public int Skip { get; set; }
    }

    public class SearchByNameRequest : MultipleRequest
    {
        public SearchByNameRequest(string name, int take = 50, int skip = 0)
            : base(take, skip)
        {
            Name = name;
        }
        public string Name { get; set; }
    }

    public class PaginationHelper<TR>
    {
        public delegate Task<TR> SearchMethodDelegate(MultipleRequest multipleRequest);

        public static async Task<TR> GetResultFromSearchAsync(SearchMethodDelegate task, Func<TR,bool> checker, int paging = 50)
        {
            int take = paging;
            int skip = 0;

            TR getterValue;

            do
            {
                var parameterInfo = task.Method.GetParameters()[0];

                var properties = parameterInfo.ParameterType.GetProperties();

                // zmena take v requestu
                // zmena skip v requestu

                getterValue = await task.Invoke(??????????????);

                skip += take;

            } while (!checker.Invoke(getterValue));

            return getterValue;
        }
    }

Volám to takhle:

Kód: [Vybrat]
        public async Task Run()
        {
            await PaginationHelper<string>.GetResultFromSearchAsync(
                async (r) => await SearchMethod(new SearchByNameRequest("Bill Clinton")),
                res => res != null,
                50);
        }

        public async Task<string> SearchMethod(SearchByNameRequest multipleRequest)
        {
            return "Bill Clinton";
        }

Tzn. v instanci toho delegátu už instance requestu je, jen nevím, v místě, kde jsou otazníky, jak ji dosadit.

Re:C# a přístup k parametru delegáta
« Odpověď #6 kdy: 27. 04. 2019, 15:30:29 »
Proc si vubec vyrabis tridu PaginationHelper a jeste navic generickou, to fakt nechapu.

Kdyz ti ty Request objekty dedi z MultipleRequest, tak snad muzes proboha udelat toto

Kód: [Vybrat]
ListCockableGuysRequest request = new ListCockableGuysRequest();
((MultipleRequest)request).take = 111;
((MultipleRequest)request).skip = 222;

Anebo:

setPagination(request, 111, 222);

public static void setPagination(MultipleRequest multipleRequest, int take, int skip) {
  multipleRequest.take = 111;
multipleRequest.skip = 222;
 
}

Naco proboha na takovou vec potrebujes jakysik genericky PaginationHelper a jeste vsude nastrkat await async?