Laden...

Erweiterungsmethode ohne Typinstanz aufrufen

Erstellt von inflames2k vor 7 Jahren Letzter Beitrag vor 7 Jahren 1.954 Views
inflames2k Themenstarter:in
2.298 Beiträge seit 2010
vor 7 Jahren
Erweiterungsmethode ohne Typinstanz aufrufen

Hallo,

ich habe spezifische Erweiterungsmethoden für Objekte, um diese zu erzeugen. Gibt es eine Möglichkeit, eine Erweiterungsmethode ohne Objektinstanz aufzurufen?

Als Beispiel könnte hier die Xml-Deserialisierung dienen:


public static T DeserializeFromXml<T>(this T o, string path)
{
    T result = default(T);

    XmlSerializer serializer = new XmlSerializer(typeof(T));
    using (FileStream stream = new FileStream(path, FileMode.Open))
    {
         result = (T)serializer.Deserialize(stream);
    }
 
   return result;
}

Was ich jetzt erreichen möchte wäre etwa folgendes:


MyObjectType myObject = MyObjectType.Deserialize(path);

Mir ist klar, dass folgendes funktionieren würde:


MyObjectType myObject = null;
myObject = myObject.Deserialize(path);

Aber das finde ich persönlich jetzt nicht so hübsch.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

1.040 Beiträge seit 2007
vor 7 Jahren

Einfach als statische Methode in der Klasse anbieten.

inflames2k Themenstarter:in
2.298 Beiträge seit 2010
vor 7 Jahren

Naja. Aber für jede Klasse die gleiche Statische Methode anbieten ist wieder blöd. Genau deshalb fand ich ja Extension-Methods dafür am besten.

Hintergrund ist ja, dass es sich in meinen Fällen jeweils immer um Funktionalitäten handelt, die bei fast jedem Objekt durchgeführt werden können.

Gerade zum Beispiel die Xml-Serialisierung ist ja ein Fall, der sich nicht auf Object X beschränkt.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

1.040 Beiträge seit 2007
vor 7 Jahren

Dann könnte eine Basisklasse deine Wahl sein. =)

public abstract class BaseClass<T> where T : BaseClass<T>, new()
{
	public static T Create()
	{
		return new T();
	}
}

public class ClassOne : BaseClass<ClassOne> { }

public class ClassTwo : BaseClass<ClassTwo> { }

var one = ClassOne.Create();
var two = ClassTwo.Create();
var oneFromBase = BaseClass<ClassOne>.Create();
var twoFromBase = BaseClass<ClassTwo>.Create();

EDIT: BaseClass<T> zum where hinzugefügt.

2.080 Beiträge seit 2012
vor 7 Jahren

Eine Erweiterungsmethode, die statisch für den Typ und nicht dessen Instanz zählt, ist nicht möglich.
Entweder Du hast eine Klasse, die solche Methoden enthält oder Du bietest die entsprechende Methode statisch pro Klasse an.

Die vermutlich einfachste aber immer noch schöne Lösung ist mMn. die von p!lle, sie verlangt aber eine Basis-Klasse.

Eine etwas komplexere dafür aber sehr flexible Alternative, die ich mal für Parse/TryParse-Methoden geschrieben habe:
Ein ParsableAttribut, was die Namen der Parse/TryParse-Methode entgegen nimmt.
Daneben eine statische Parser-Klasse, die für den angegebenen Typ dieses Attribut abruft und anhand des Namens die Methode aufruft.
So habe ich bei der Nutzung nur eine Stelle, die ich kennen muss: Die Parser-Klasse
Ob ein Typ das Parsen unterstützt, kann über das ParsableAttribut fest gelegt werden.

Das Konzept ließe sich auch eine Deserialize-Methode übertragen.
So hättest Du dann z.B. eine Klasse Deserializer und die Methode Deserialize, welche den Ziel-Typ und die Quell-Datei entgegen nimmt.
Sie schaut dann, ob sie eine Deserialize-Methode (z.B. mit Hilfe eines entsprechenden Attributs) mit der korrekten Definition finden kann und ruft sie dann auf.

So klappt das auch generisch, ohne dass Du den Typ kennen musst und eine Erweiterung ist nur in der Ziel-Klasse nötig. Eine Basis-Klasse brauchts nicht, aber man ist an Attribute und damit Metadaten gebunden.
Das könnte man auch ohne viel Aufwand so erweitern, dass in dem Attribut optional noch die Klasse angegeben werden kann, wo die Methode gesucht werden soll.

Bei Bedarf kann ich meine Parse/TryParse-Lösung mal anhängen.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

D
985 Beiträge seit 2014
vor 7 Jahren

Oder eben so


public static T DeserializeFromXml<T>(this string path)
{
    T result = default(T);

    XmlSerializer serializer = new XmlSerializer(typeof(T));
    using (FileStream stream = new FileStream(path, FileMode.Open))
    {
         result = (T)serializer.Deserialize(stream);
    }

   return result;
}

string filename = "something.xml";
Foo foo = filename.DeserializeFromXml<Foo>(); 

😁

Ob das sinnvoll ist muss jeder selber entscheiden

T
2.224 Beiträge seit 2008
vor 7 Jahren

Ich würde das eher als Erweiterungsmethode für FileInfo umsetzen als direkt von String 😕
Da der String alles sein kann(Dateipfad, Name, Langer Text etc.) wäre nicht wirklich klar, ob die Deserialisierung funktioniert.

Bei einer Extention auf FileInfo kann man alles in einem Rutsch abfragen und kann auch gleich prüfen ob die Datei vorhanden ist, man die Rechte zum lesen hat etc.

@Sir Rufo
Die Umsetzung sieht soweit super aus, würde ich direkt verwenden.
Nur halt eben nicht mit this string path sondern this FileInfo file.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.