Laden...

Delegate als Constraints

Erstellt von Scavanger vor 6 Jahren Letzter Beitrag vor 6 Jahren 1.358 Views
Scavanger Themenstarter:in
309 Beiträge seit 2008
vor 6 Jahren
Delegate als Constraints

Servus zusammen,

bis jetzt hatte ich in einem Projekt eine Methode die einen Delegaten zurückgibt, mir der folgenden Signatur:
Marshal.GetDelegateForFunctionPointer(), funktioniert genau so.


public Delegate GetDelegate(string foo, Type t)
{ 
//...
}

Benutzt wird sie so:


MyDelegate myDelegate = (MyDelegate)obj.GetDelegate("foo", typeof(MyDelegate );

Was ich nicht sehr hübsch finde, der Cast und das typeof() stören mich irgendwie, für so etwas wurden doch Generics erfunden, aber warum kann ich keine Delegaten als Constraints verwenden?
Dadurch kann ich nicht auf den richtigen Typ casten.

Das ist was ich gerne hätte:


public TDelegate GetDelegate<TDelegate>(string foo) where TDelegate : Delegate
{
     return (TDelegate)GetDelegate(foo, typeof(TDelegate));
}

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}

4.931 Beiträge seit 2008
vor 6 Jahren

Die unter Compilerfehler CS0702 aufgelisteten Typen sind alles nur Meta-Typen, d.h. direkt kann man davon nicht ableiten und daher auch keinen Constraint damit benutzen.
Du könntest aber (wie unter Anyone know a good workaround for the lack of an enum generic constraint? beschrieben) mittels Runtime-Check den Typ überprüfen (s. Check if an object is a delegate).

Eine andere Möglichkeit wäre die Verwendung von unconstrained-melody, s. dessen Kurz-Doku Generic constraints for enums and delegates (ich weiß aber nicht, ob das wirklich für ein Produktivprojekt geeignet ist?).

Scavanger Themenstarter:in
309 Beiträge seit 2008
vor 6 Jahren

unconstrained-melody ist schon etwas mit Kanonen auf Spatzen schießen, es geht nur um eine Methode in einem Modul.

Ja danke, der Runtime check geht relativ problemlos mit


if (!typeof(Delegate).IsAssignableFrom(typeof(TDelegate)))
    throw new InvalidOperationException();

aber wie kann ich den Delegaten (ich kann erst hier mit dem konkreten Typ arbeiten, es ist im Endeffekt ein nativer Funktionszeiger, mit Marshal.GetDelegateForFunctionPointer erzeugt) auf den konkreten Typ casten?

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}

16.807 Beiträge seit 2008
vor 6 Jahren

Hättest Du lust zu beschreiben, was Du damit eigentlich erreichen willst?
Hab das Gefühl, dass es da eine bessere Lösung für das Ziel gibt.

Scavanger Themenstarter:in
309 Beiträge seit 2008
vor 6 Jahren

Ich beschäftige mich nach langer Zeit mal wieder mit einem alten Projekt: MemoryModule.net (https://github.com/Scavanger/MemoryModule.net).
Es geht darum eine native DLL aus dem Speicher zu laden, ist ein .net-Port des ursprünglich in C geschriebenen Moduls. (https://github.com/fancycode/MemoryModule)

Also ich bekomme einen Funktionszeiger auf eine native Funktion (der geladenen DLL) und wandle ihn mit Marshal.GetDelegateForFunctionPointer() in einen Delegaten.

Wie gesagt, eine Funktion mit Generics wäre schön, dann wäre die Klasse sehr handlich, der Funktionsaufruf mit dem Cast und typeof wirkt doch recht altbacken.

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}

W
195 Beiträge seit 2008
vor 6 Jahren

Hilft Dir das hier vielleicht weiter?

Marshal.GetDelegateForFunctionPointer<TDelegate>()

Scavanger Themenstarter:in
309 Beiträge seit 2008
vor 6 Jahren

*Klatsch-ans-Hirn* 😁

Danke, damit geht's natürlich easy.
Man sollte doch öfters mal schauen was die neuen Frameworkversionen so bieten. Das Projekt war noch auf dem alten 3.5er, da gab es die generische Version noch nicht.

Ich hab inzwischen einen "nasty Hack" gefunden wie es auch mit den alten Version funktioniert:


public TDelegate GetDelegate<TDelegate>(string foo) where TDelegate : class
{
     // Runtimeprüfung
     return (TDelegate)(object)Marshal.GetDelegateForFunctionPointer( ... );
}

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}