Pomoc s Reflexí v C#

zemla

Pomoc s Reflexí v C#
« kdy: 16. 11. 2018, 16:17:01 »
Dobrý den - jde pomocí reflexe v C# v metodě třídy zjistit název třídy a této metody prosím?
Příklad:

Kód: [Vybrat]
public class ClassA
{
     public void Method1()
     {
          Console.Write(....pomoci reflexe.....);
     }
}

s výstupem něco na způsob:

Kód: [Vybrat]
"ClassA::Method1"

Víte někdo jak na to?
Díky



zemla

Re:Pomoc s Reflexí v C#
« Odpověď #2 kdy: 16. 11. 2018, 16:49:42 »
Díky, funguje.

Zjistil jsem, že pro třídu můžu použít i this.GetType().

Teď to jdu luštit, abych zjistil, třídu a metodu toho, kdo to zavolal.:-)

zemla

Re:Pomoc s Reflexí v C#
« Odpověď #3 kdy: 16. 11. 2018, 17:14:01 »
Takže když budu mít jistotu, že moji metodu někdo volá :-) tak funguje i toto :

Kód: [Vybrat]
        public async Task Method1()
        {
            var stackTrace = new StackTrace();

            var count = stackTrace.FrameCount;
            var frame = stackTrace.GetFrames()?[count-1];
            var method = frame?.GetMethod();

            Console.WriteLine(method?.ReflectedType?.Name + "." + method?.Name);
        }

Jen prosím o názor, proč by metoda (v budoucnu to zapíše do StreamWriteru) mohla/neměla být async? Proč dneska každej nadúžívá async/await nevíte prosím?

JmJ

  • ****
  • 315
    • Zobrazit profil
Re:Pomoc s Reflexí v C#
« Odpověď #4 kdy: 16. 11. 2018, 18:18:05 »
To zalezi na tobe, co tvuj program ma delat ;-)

Pokud bys to napsal spravne a fakt by ten zapis do streamu probihal na pozadi, pak by ti mohlo dojit k tomu, ze poradi dat ve streamu bude jine, nez bylo poradi volani te funkce, ktera mela do streamu neco zapsat. Pokud v tom miste, odkud budete tu funkci pro zapis volat, chcete mit minimalni zdrzeni pri volani te zapisovaci funkce, tak treba to zapisovani na pozadi muze byt resenim. Ale jak sem psal, zapisy muzou byt prehazene.

Pokud chci nezdrzovat zapisy a mit spravne razeni, tak proste hodim to co, se ma zapsat, do fronty (bufferu) a na pozadi mi bezi proces, ktery frontu vybira a zapisuje data do streamu.

async await na to neni k nicem, to je takova obezlicka, ktera vam usetri nejake kodovani, ale ktera spohlive mate naprostou vetsinu lidi. Ja to nekdy pouzivam, ale moc casto zase ne ;-).

Priznam se, ze vam to nerknu ted z placu na 100%, ale hadal bych, ze tak ja jste to zapsal vy, by to ani na pozadi nebezelo ;-). V podstate jde o to, ze ta vase metoda nema v sobe zadny bezici Task. Sice to mate jako async metodu, ktera vraci Task, ale v te metode zadny bezici task neni. Dokonce si myslim,  ze vam compiler na to rekne, ze v te metode nemate zadny await na metodu, ktera vraci Task. Uplne "uvnitr" vsech await volani musi byt volani metody cca Task MojeAsyncMetoda() { return Task.Run(() => muj_hrozny_vypocet());} .


zemla

Re:Pomoc s Reflexí v C#
« Odpověď #5 kdy: 16. 11. 2018, 18:56:44 »
Ano, neběží to na pozadí, zavolal jsem to s GetAwaiter().GetResult(), tzn synchronně.

zemla

Re:Pomoc s Reflexí v C#
« Odpověď #6 kdy: 16. 11. 2018, 19:05:41 »
Ale teď mě víc trápí jiná věc:

Kód: [Vybrat]
    public class Program
    {
        private readonly int _creationDate;

        public Program()
        {
            _creationDate = DateTime.Now.Millisecond;
        }

        public override int GetHashCode()
        {
            return _creationDate;
        }

        public async Task<string> Method1()
        {
            var stackTrace = new StackTrace();

            var count = stackTrace.FrameCount;
            var frame = stackTrace.GetFrames()?[count - 1];
            var method = frame?.GetMethod();

            return method?.ReflectedType?.Name + "(" + method?.ReflectedType?.GetHashCode() + ")." + method?.Name;
        }

        public static void Main(string[] args)
        {
            Console.WriteLine(new Program().Method1().GetAwaiter().GetResult());
            Console.WriteLine(new Program().Method1().GetAwaiter().GetResult());

            Console.ReadLine();
        }
    }

Proč se prosím nevolá moje přetížená GetHashCode metoda? A furt to vždycky vrací ten samý hash code ?

zemla

Re:Pomoc s Reflexí v C#
« Odpověď #7 kdy: 17. 11. 2018, 00:02:54 »
I takhle se to da doprasit:

Kód: [Vybrat]
        public async Task<string> Method1()
        {
            var stackTrace = new StackTrace();

            var count = stackTrace.FrameCount;
            var frame = stackTrace.GetFrames()?[count - 1];
            var method = frame?.GetMethod();

            return method?.ReflectedType?.Name + "(" + method?.ReflectedType?.
                       InvokeMember("GetHashCode", BindingFlags.InvokeMethod, null, this, null) + ")."
                       + method?.Name;
        }

Jde to prosim udelat nejak jinak ? :-(

Re:Pomoc s Reflexí v C#
« Odpověď #8 kdy: 17. 11. 2018, 13:46:18 »
...
Uplne "uvnitr" vsech await volani musi byt volani metody cca Task MojeAsyncMetoda() { return Task.Run(() => muj_hrozny_vypocet());} .

Omlouvám se za trochu offtopic, ale nedá mi to.
Výše napsané není pravda a je to podle mně jeden z těch méně vhodných příkladů jak Async/Await používat/implementovat.

Ve zkratce:
Pro CPU bound tasky async/await nemá moc smysl, respektive výhody.
Naopak u IO to dává async/await velký smysl, pokud se tedy úplně "uvnitř" použijí "nativní" async I/O funkce (na místo Task.Run( .. synchroní I/O ..). Umožňuje to mít spuštěno najednou více tasků než je (najednou) využito vláken což šetří zdroje.

Také je dobré si pamatovat že samotné await/await nevynucuje to že práce bude provedena v jiném vlákně(i když to tak někdy může dopadnout). Do hry tu vstupuje koncept SynchronizationContext (kde lze například vynutit že vše bude bude probíhat pouze v jednom vlákně).

Jiný pohled, z hlediska i/o: pokud čteme ze socketu a data jsou již přijata, tak předávat práci(čtení ze socketu do bufferu) "na jiné vlákno" není zrovna hospodárné, proto se čtení se může provést synchroně, a to i včetně potenciálně CPU bound kódu který za povelem na čtení následuje.

Popsat všechny výhody/nevýhody z různých pohledů, to je jistě na několik článků a doporučuji googlit.
Ale ani ofici8ln9 dokumentace není pro začátek špatná, třeba : https://docs.microsoft.com/cs-cz/dotnet/csharp/programming-guide/concepts/async/index

zemla

Re:Pomoc s Reflexí v C#
« Odpověď #9 kdy: 17. 11. 2018, 13:56:51 »
I takhle se to da doprasit:

Kód: [Vybrat]
        public async Task<string> Method1()
        {
            var stackTrace = new StackTrace();

            var count = stackTrace.FrameCount;
            var frame = stackTrace.GetFrames()?[count - 1];
            var method = frame?.GetMethod();

            return method?.ReflectedType?.Name + "(" + method?.ReflectedType?.
                       InvokeMember("GetHashCode", BindingFlags.InvokeMethod, null, [b]this[/b], null) + ")."
                       + method?.Name;
        }

Jde to prosim udelat nejak jinak ? :-(

Vadí mi tam to "this", má jít v budoucnu o Logger, a ten se mi nechce dotazovat na instanci volajícího.
Má prosím někdo nějaký nápad?

oss

Re:Pomoc s Reflexí v C#
« Odpověď #10 kdy: 17. 11. 2018, 17:17:49 »
Dobrý den - jde pomocí reflexe v C# v metodě třídy zjistit název třídy a této metody prosím?
Příklad:

Kód: [Vybrat]
public class ClassA
{
     public void Method1()
     {
          Console.Write(....pomoci reflexe.....);
     }
}

s výstupem něco na způsob:

Kód: [Vybrat]
"ClassA::Method1"

Víte někdo jak na to?
Díky

Ide to este jednoduhsie:
Kód: [Vybrat]
public void DoProcessing()
{
    TraceMessage("Something happened.");
}

public void TraceMessage(string message,
        [System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
        [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
        [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
    System.Diagnostics.Trace.WriteLine("message: " + message);
    System.Diagnostics.Trace.WriteLine("member name: " + memberName);
    System.Diagnostics.Trace.WriteLine("source file path: " + sourceFilePath);
    System.Diagnostics.Trace.WriteLine("source line number: " + sourceLineNumber);
}

// Sample Output:
//  message: Something happened.
//  member name: DoProcessing
//  source file path: c:\Users\username\Documents\Visual Studio 2012\Projects\CallerInfoCS\CallerInfoCS\Form1.cs
//  source line number: 31
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callermembernameattribute?view=netframework-4.7.2

oss

Re:Pomoc s Reflexí v C#
« Odpověď #11 kdy: 17. 11. 2018, 17:19:39 »
To zalezi na tobe, co tvuj program ma delat ;-)

Pokud bys to napsal spravne a fakt by ten zapis do streamu probihal na pozadi, pak by ti mohlo dojit k tomu, ze poradi dat ve streamu bude jine, nez bylo poradi volani te funkce, ktera mela do streamu neco zapsat. Pokud v tom miste, odkud budete tu funkci pro zapis volat, chcete mit minimalni zdrzeni pri volani te zapisovaci funkce, tak treba to zapisovani na pozadi muze byt resenim. Ale jak sem psal, zapisy muzou byt prehazene.

Pokud chci nezdrzovat zapisy a mit spravne razeni, tak proste hodim to co, se ma zapsat, do fronty (bufferu) a na pozadi mi bezi proces, ktery frontu vybira a zapisuje data do streamu.

async await na to neni k nicem, to je takova obezlicka, ktera vam usetri nejake kodovani, ale ktera spohlive mate naprostou vetsinu lidi. Ja to nekdy pouzivam, ale moc casto zase ne ;-).

Priznam se, ze vam to nerknu ted z placu na 100%, ale hadal bych, ze tak ja jste to zapsal vy, by to ani na pozadi nebezelo ;-). V podstate jde o to, ze ta vase metoda nema v sobe zadny bezici Task. Sice to mate jako async metodu, ktera vraci Task, ale v te metode zadny bezici task neni. Dokonce si myslim,  ze vam compiler na to rekne, ze v te metode nemate zadny await na metodu, ktera vraci Task. Uplne "uvnitr" vsech await volani musi byt volani metody cca Task MojeAsyncMetoda() { return Task.Run(() => muj_hrozny_vypocet());} .

nepochopil si princip async/await vid komentar vysie.

zemla

Re:Pomoc s Reflexí v C#
« Odpověď #12 kdy: 17. 11. 2018, 18:09:17 »
Dobrý den - jde pomocí reflexe v C# v metodě třídy zjistit název třídy a této metody prosím?
Příklad:

Kód: [Vybrat]
public class ClassA
{
     public void Method1()
     {
          Console.Write(....pomoci reflexe.....);
     }
}

s výstupem něco na způsob:

Kód: [Vybrat]
"ClassA::Method1"

Víte někdo jak na to?
Díky

Ide to este jednoduhsie:
Kód: [Vybrat]
public void DoProcessing()
{
    TraceMessage("Something happened.");
}

public void TraceMessage(string message,
        [System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
        [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
        [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
    System.Diagnostics.Trace.WriteLine("message: " + message);
    System.Diagnostics.Trace.WriteLine("member name: " + memberName);
    System.Diagnostics.Trace.WriteLine("source file path: " + sourceFilePath);
    System.Diagnostics.Trace.WriteLine("source line number: " + sourceLineNumber);
}

// Sample Output:
//  message: Something happened.
//  member name: DoProcessing
//  source file path: c:\Users\username\Documents\Visual Studio 2012\Projects\CallerInfoCS\CallerInfoCS\Form1.cs
//  source line number: 31
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callermembernameattribute?view=netframework-4.7.2

No to je otázka, jestli to takhle jde, když to převedu do vaší řeči, tak u toho, kdo volá Trace message mám specifický požadavek - mám tam přetíženou GetHashCode, abych u jedné třídy navzájem odlišil různé instance. (v metodě Trace). A co jsem potřeboval je, abych v konstruktoru volajícího, ať bude architektura nějaká prostě, nemusel do TraceMessage předávat instanci jako "this".

Fakt bych chtěl zavolat LogInfo, LogError nebo LogWarning pouze s parametrem Message. A tady jsem narazil.:-(

zemla

Re:Pomoc s Reflexí v C#
« Odpověď #13 kdy: 17. 11. 2018, 18:19:31 »
Už se do toho začínám zamotávat. Bude třída Logger, třeba statická. Tato třída bude implementovat metody Log... Volající typu T atd budou mít více instancí a já logy z jednotlivých instancí T budu potřebovat groupovat, proto jsem chtěl přetížit metodu GetHashCode volajícího.

Zatím to vypadá, že budu muset např v konstruktoru T volat něco jako Logger.Init(unikátní_id)

JmJ

  • ****
  • 315
    • Zobrazit profil
Re:Pomoc s Reflexí v C#
« Odpověď #14 kdy: 18. 11. 2018, 08:53:47 »
...
Uplne "uvnitr" vsech await volani musi byt volani metody cca Task MojeAsyncMetoda() { return Task.Run(() => muj_hrozny_vypocet());} .

Omlouvám se za trochu offtopic, ale nedá mi to.
Výše napsané není pravda a je to podle mně jeden z těch méně vhodných příkladů jak Async/Await používat/implementovat.

Ve zkratce:
Pro CPU bound tasky async/await nemá moc smysl, respektive výhody.
Naopak u IO to dává async/await velký smysl, pokud se tedy úplně "uvnitř" použijí "nativní" async I/O funkce (na místo Task.Run( .. synchroní I/O ..). Umožňuje to mít spuštěno najednou více tasků než je (najednou) využito vláken což šetří zdroje.

Také je dobré si pamatovat že samotné await/await nevynucuje to že práce bude provedena v jiném vlákně(i když to tak někdy může dopadnout). Do hry tu vstupuje koncept SynchronizationContext (kde lze například vynutit že vše bude bude probíhat pouze v jednom vlákně).

Jiný pohled, z hlediska i/o: pokud čteme ze socketu a data jsou již přijata, tak předávat práci(čtení ze socketu do bufferu) "na jiné vlákno" není zrovna hospodárné, proto se čtení se může provést synchroně, a to i včetně potenciálně CPU bound kódu který za povelem na čtení následuje.

Popsat všechny výhody/nevýhody z různých pohledů, to je jistě na několik článků a doporučuji googlit.
Ale ani ofici8ln9 dokumentace není pro začátek špatná, třeba : https://docs.microsoft.com/cs-cz/dotnet/csharp/programming-guide/concepts/async/index

Popravde moc nevim, co z toho, zo jsem puvodne psal, povazujete za nepravdu. Ve vami odkazovanem prikladu se napr. pracuje s http clientem, ktery ma asynchronni metody, ktere primo vraceji tasky, takze se primo tyto metody daji volat pres async. Jak to rozporuje to, co jsem napsal? Dale dotazovatel resil asynchronni zapisy, vy hovorite o asynchronnim cteni. Tady souvislost s mou odpovedi take uplne nevidim. Myslim, ze jsem ani explicitne neuvadel, zda tasky vzdy bezi jako thready nebo ne. V cem tedy prosim spociva nepravdivost me odpovedi? Rad se poucim.