2016-05-06 16 views
1

Ich frage mich, ob es möglich ist, eine C# -Methode zu schreiben, die eine Kombination verschiedener Argumenttypen verwenden kann.Methode mit Kombinationen verschiedener Argumenttypen

Zum Beispiel würde diese Methode vier überladene Methoden zu einer kombinieren.

+4

Was ist der Vorteil? Stellen Sie mehrere Überladungen mit verschiedenen Signaturen bereit. –

+2

Intern müsste man Code schreiben, um herauszufinden, um welchen Typ es sich bei jedem Parameter handelt und wie man damit umgehen kann. An diesem Punkt können Sie sowieso die separaten Methodenüberladungen verwenden. –

+0

'JObject' und' File' Klassen hat ziemlich verschiedene Mitglieder und implementiert keine gemeinsame Schnittstelle. Also ist diese "kombinierte" Methode voll von Spaghetti Code wie 'if (jsonOne ist Datei) {.....} sonst if (isonOne ist JObject) {...}' –

Antwort

6

Nein, Sie können keine einzelne Methodenüberladung erstellen, die einen von zwei festen Typen für einen bestimmten Parameter akzeptiert.

Das Beste, was Sie (während noch mehr Überlastungen zu vermeiden) tun können, ist eine neue Art zu schaffen, mit dem Sie eine Instanz durch einen von zwei verschiedenen Arten schaffen könnten, und eine Instanz von dass zu akzeptieren.

public class MyJSON 
{ 
    public MyJSON(JObject json) 
    { 
     FirstOption = json; 
     FirstOptionValid = true; 
    } 
    public MyJSON(File json) 
    { 
     SecondOption = json; 
     SecondOptionValid = true; 
    } 
    public JObject FirstOption { get; private set; } 
    public bool FirstOptionValid { get; private set; } 
    public File SecondOption { get; private set; } 
    public bool SecondOptionValid { get; private set; } 

    public static implicit operator MyJSON(File json) 
    { 
     return new MyJSON(json); 
    } 
    public static implicit operator MyJSON(JObject json) 
    { 
     return new MyJSON(json); 
    } 
} 

Sie könnten sogar implizite Konvertierungen von JObject und File-MyJSON erstellen, so dass ein Benutzer tatsächlich ein JObject oder File Objekt MyMethod, ohne auch nur, um überhaupt einen Vermittler Objekt explizit zu konstruieren passieren kann.

In der Tat, es ist eigentlich sehr einfach durch Verwendung von Generika dies für jede festgelegte Anzahl von Arten zu verallgemeinern:

public class Option<T1, T2> 
{ 
    public Option(T1 value) 
    { 
     FirstOption = value; 
     FirstOptionValid = true; 
    } 
    public Option(T2 value) 
    { 
     SecondOption = value; 
     SecondOptionValid = true; 
    } 
    public T1 FirstOption { get; private set; } 
    public bool FirstOptionValid { get; private set; } 
    public T2 SecondOption { get; private set; } 
    public bool SecondOptionValid { get; private set; } 

    public static implicit operator Option<T1, T2>(T2 value) 
    { 
     return new Option<T1, T2>(value); 
    } 
    public static implicit operator Option<T1, T2>(T1 value) 
    { 
     return new Option<T1, T2>(value); 
    } 
} 

Wir haben jetzt Ihre Methode als schreiben:

public static void MyMethod(Option<JObject, File> json1, Option<JObject, File> json2) 
+0

Dies ist, obwohl, wie bereits erwähnt, es viel sinnvoller wäre, mehrere Überladungen mit unterschiedlichen Signaturen für jeden benötigten Typ zu haben. – GJKH

+0

@ GJKH Das hängt von der Situation ab. Mehrere Überladungen wären für einen Parameter mit zwei Optionen in Ordnung, aber er skaliert exponentiell mit der Anzahl der Optionen für jeden gegebenen Parameter und der Anzahl der Parameter, während diese linear skaliert wird, wenn also mehr als ein paar Typen oder mehr als a wenige Parameter, dies wäre wahrscheinlich einfacher. – Servy

+0

Dies kann so erweitert werden, dass 'MyJSON' die Methoden dieser beiden Typen so aufdeckt, dass Sie nicht wissen müssen, ob es aus einem' JObject' oder 'File' erstellt wurde. Aber genau das hängt davon ab, wie unterschiedlich die Methode sie behandelt. – juharr

1

Zwei mögliche, aber schmutzige Lösungen:

One (Annahme Objekte und Typprüfung)

public static void MyMethod(object one, object two) 
{ 
    if(one is JObject) // handle 
    else if(one is File) // handle 
    else throw SomeException(); 
    ... 

gleiche gilt für die zweite param

Zwei: optional params

public static void MyMethod(JObject jone = null, File fone = null, 
    JObject jtwo = null, File ftwo = null) 
{ 
    if(jone == null && fone == null) 
     throw SomeException(); 
    else 
     // use set values and do stuff 
    ... 
+0

ja, die Punkte sollten anzeigen, dass ... Sie müssen es für jeden Parameter tun, habe ich den zweiten Teil weggelassen. –

+0

aktualisiert meine Antwort für bessere Lesbarkeit –

+0

Beachten Sie, dass * beide * dieser Lösungen statische Sicherheit verlieren, die ersten verlieren alle Arten von Sicherheit vollständig, so dass die Methode * extrem * schwierig, richtig zu verwenden, und die zweite nicht in der Lage, die Beschränkung durchzusetzen dass nur eines von jedem Objektpaar einen Wert haben sollte (was bedeutet, dass "null" niemals ein gültiger Wert sein kann, was möglicherweise keine korrekte Annahme ist). Es skaliert auch * sehr * schlecht mit der Anzahl der möglichen Typen für jeden Parameter und wäre für einen Aufrufer noch verwirrender, wenn die Typoptionen für jeden Parameter nicht gleich sind. – Servy

0

Siehe Code unten:

interface IDo { 
    void DoSomething(); 
} 

class MyFile : File, IDo { 
    void DoSomething() { 
     // blah blah 
    } 
} 

class MyJObject : JObject, IDo { 
    void DoSomething() { 
     // blah blah 
    } 
} 

public static void MyMethod<T1, T2>(T1 one, T2 two) 
    where T1 : IDo 
    where T2 : IDo 
{ 
    one.DoSomething(); 
    two.DoSomething(); 
} 

Wenn Datei- und/oder JObject versiegelt sind, dann Haltung anstelle von Vererbung :

class MyFile : IDo { 
    File file; 
    void DoSomething() { 
     // blah blah 
    } 
} 

class MyJObject : IDo { 
    JObject jObject; 
    void DoSomething() { 
     // blah blah 
    } 
} 
Verwandte Themen