2015-12-23 11 views
10

Ich möchte eine Schnittstelle zu einigen integrierten Typen hinzufügen. Ich habe eine Schnittstelle, IConcludable, die ich als Einschränkung für Conclusion<T> verwende. Ich habe keine Ahnung, wie ich das angehen soll oder ob es überhaupt möglich ist.Gibt es eine Möglichkeit, einen integrierten Typ zu erweitern, um eine Schnittstelle zu erben?

Basislayout

public interface IConcludable { } 

public struct Conclusion<T> where T : IConcludable 
{ 
    public bool IsSuccessful; 
    public T Result; 

    // Constructors, members, etc. 
} 

public class ErrorReport : IConcludable { ... } 

public class MathArg : IConcludable { ... } 

public class ParseResult : IConcludable { ... } 

Implementierung

public Conclusion<ParseResult> ParseInput (string input) 
{ 
    // Parse input... 
    // Initialize ParseResult object... 

    return new Conclusion<ParseResult>(result); 
} 

Problem

Als ich den endgültigen Wert zu erhalten, ist es ein eingebauter Typ wie int, double, string, bool usw. Ich möchte Conclusion<T> als Rückkehr benutzen, weil ich eine Klasse, die Fehlermeldungen verarbeitet, wenn die Eingabezeichenfolge ist ungültig:

if (conclusion.ReturnObject is ErrorReport) 
{ 
    ErrorManager errorManager = new ErrorManager(); 
    errorManager.Resolve(conclusion); 
} 

Forschung

Ich sah in Einschränkungen.

Es scheint, dass Beschränkungen nur zusammen addieren, so eingeschlossen sind die Schnittstellen von jedem eingebauten Typ, den ich würde erfordern, müssen einen Berg von Methoden definieren, die etwas nicht mit dem zu tun haben meine Conclusion Struktur


Erweiterungsmethoden

Diese tatsächlich das Verhalten von eingebauten Typen ändern. Es ist nicht, was ich suche, weil meine Schnittstelle, IConcludable, keine Methoden hat.

Ersetzen eingebauten Typen

Nicht möglich. Ich muss das Verhalten dieser Typen jedoch nicht ändern. Ich möchte nur eine leere Schnittstelle hinzufügen.

Es scheint nichts in Bezug auf das Hinzufügen einer Schnittstelle zu einem eingebauten Typ zu geben. Ich bin mir nicht sicher, ob "Vererbung" gemeint ist. Ist das möglich?

bearbeiten

bessere Erklärung der Schlussfolgerung struct

ich den Abschluss struct als Rück Objekt verwenden in den meisten meine Methoden. Dies liegt daran, dass ich Delegierte verwende. Siehe den tatsächlichen Code der folgenden Objekte:

public delegate Conclusion<T> Validator<T>(T subclass) where T : IVerifiable<T>; 

public delegate Conclusion<BaseFunction> Executor(BaseFunction subclass); 

public struct Conclusion<T> where T : IConcludable 
{ 
    public bool IsSuccessful; 
    public T ReturnObject; 

    public Conclusion(T returnObject) 
    { 
     this.ReturnObject = returnObject; 
     this.IsSuccessful = returnObject is Error ? false : true; 
    } 
} 

public class BaseFunction : IVerifiable<BaseFunction>, IConcludable 
{ 
    public List<BaseArgument> Args; 
    public Executor Executing; 
    public Validator<BaseFunction> Validating; 
    public string UserInput; 

    public Conclusion<BaseFunction> Validate(BaseFunction subclass) 
    { 
     if (this.Validating != null) 
     { 
      return Validating(subclass); 
     } 
     else 
     { 
      StringBuilder message = new StringBuilder(); 
      message.Append("A Validating delegate has not been assigned."); 

      throw new InvalidOperationException(message.ToString()); 
     } 
    } 

    public Conclusion<BaseFunction> Execute(BaseFunction subclass) 
    { 
     if (this.Executing != null) 
     { 
      return this.Executing(subclass); 
     } 
     else 
     { 
      StringBuilder message = new StringBuilder(); 
      message.Append("An Executing delegate has not been assigned."); 

      throw new InvalidOperationException(message.ToString()); 
     } 
    } 
} 

public class Function<T> : BaseFunction 
{ 
    public T Result; 

    public Function() 
    { 
     base.Args = new List<BaseArgument>(); 
    } 
} 

public class BaseArgument : IVerifiable<BaseArgument>, IConcludable 
{ 
    public string Role; 
    public string UserInput; 
    public int Position; 
    public Validator<BaseArgument> Validating; 

    public Conclusion<BaseArgument> Validate(BaseArgument subclass) 
    { 
     if (this.Validating != null) 
     { 
      return Validating(subclass); 
     } 
     else 
      throw new InvalidOperationException(); 
    } 
} 

public class Argument<T> : BaseArgument 
{ 
    public T Value; 

    public Argument(int position) 
    { 
     base.Position = position; 
    } 
} 

public static class ExecutionHandler 
{ 
    public static Conclusion<BaseFunction> Sum(BaseFunction subclass) 
    { 
     subclass = (Function<double>)subclass; 

     // Execution code. 

     return new Conclusion<BaseFunction>(subclass); 
    } 

    public static Conclusion<BaseFunction> Concatenate(BaseFunction subclass) 
    { 
     subclass = (Function<double>)subclass; 

     // Execution code. 

     return new Conclusion<BaseFunction>(subclass); 
    } 
} 

Wenn ich mehr posten muss, werde ich. aber es ist wirklich viel zu sehen. Der Rückgabetyp der Methoden, die von allen Delegaten zugewiesen werden, die ich verwende, haben einen Rückgabetyp Conclusion<T>, so dass ich ein Rückgabeobjekt sowie einen Fehler haben kann, wenn einer auftritt. Die Funktionen im obigen Code geben Conclusion<BaseFunction> zurück, aber diese Rückgabe wird in ein Objekt Addend<T> konvertiert, wenn es sich um eine Zahl handelt. Wenn es ein Teil eines anderen Funktionstyps ist, der einen string oder bool oder einen anderen Typ zurückgibt, wird es in einen anderen Typ von Klasse konvertiert. Am Ende einer numerischen Berechnung ist die Rückgabe etwa Conclusion<int> oder Conclusion<double>. Also das Hinzufügen von int und double zu der IConcludable Schnittstelle ist was ich versuche zu tun.

bessere Erklärung der Anwendung

Ich bin eine C# Konsolenanwendung zu schreiben. Es nimmt Eingaben vom Benutzer und schreibt eine Antwort. Die Eingabe ähnelt Excel-Formeln: Sum(5, 15, Average(2, 3), 5) oder Concatenate("5 + 5 = ", Text(Sum(5, 5))). Die Eingabezeichenfolge wird validiert, analysiert und gibt ein Ergebnis zurück.

+0

wie ich in Ihrer Implementierung sehen, Sie zurückgeben Fazit . Aber du hast auch gesagt *** Wenn ich den endgültigen Wert bekomme, ist es ein eingebauter Typ wie int, double, string, bool, usw. *** Ich verstehe diesen Teil nicht. –

+0

Obwohl Ihre Frage sehr gut gestellt ist, denke ich, dass Sie die * tatsächliche Frage * schärfen sollten, da es derzeit nicht klar ist, was nicht mit diesem Konstrukt funktioniert. –

+1

Ist das nicht Szenario für ** Adaptermuster **? –

Antwort

1

AKTUALISIERT (ADD erklärungs)

Wie gewünscht, ich möchte ein bisschen mehr über meine letzte Antwort erklären.

Anforderungen

  • Der Conclusion Bedarf sowohl Typ und Referenz Werttyp
  • Generisches
  • Wertetypen unterstützen: alle numerischen Datentypen (int, kurz, lang, usw.), boolean, char, date ....
  • Referenztypen: Zeichenfolge und benutzerdefinierte Klasse (in OPs Beispiel, IConcludable)

Lösung:

  • eine Basisklasse einführen (AbstractConclusion), die Object als generische Eingabe akzeptiert
  • die Logik Basisklasse für die Wiederverwendung
  • zwei neue konkrete Implementierungen bewegen
  • das akzeptiert struct und IConcluable (haben Sie die Möglichkeit, mehr Implementierung hinzuzufügen, zB: string)
  • Die vererbten Klassen sind in der Lage auf alle Methoden der Basisklasse

ORIGINAL ANTWORT:

Sie die Logik in AbstractConclusion Klasse setzen, und haben zwei Implementierungen davon (Conclusion die IConcludeable akzeptiert und PrimitiveConclusion die struct Datentyp)

Siehe Codebeispiel unten akzeptiert:

void Main() 
{ 
    PrimitiveConclusion<int> primitiveConclusion = new PrimitiveConclusion<int>(1); 
    Conclusion<ParseResult> parseResultConclusion = new Conclusion<ParseResult>(new ParseResult {}); 

    Console.WriteLine($"{primitiveConclusion.Result.GetType()}"); 
    Console.WriteLine($"{parseResultConclusion.Result.GetType()}"); 
} 

public class TestClass 
{ 
    public Conclusion<ParseResult> ParseInput(string input) 
    { 
     return new Conclusion<ParseResult>(null); 
    } 
} 

public interface IConcludable { } 

public abstract class AbstractConclusion<T> 
{ 
    public AbstractConclusion(T t) 
    { 
     IsSuccessful = t != null; 
     Result = t; 
    } 
    public bool IsSuccessful; 
    public T Result; 
} 

public class Conclusion<T> : AbstractConclusion<T> where T : IConcludable 
{ 
    public Conclusion(T t) : base(t) 
    { 
    } 
} 


public class PrimitiveConclusion<T> : AbstractConclusion<T> where T : struct 
{ 
    public PrimitiveConclusion(T t) : base(t) 
    { 
    } 
} 


public class ParseResult : IConcludable { } 
+0

kienct89, ich versuche zu verstehen, was die abstrakte Klasse macht. Es scheint, als ob es irgendeinen Wert annehmen würde. Wie "T" ist äquivalent zu "Objekt". Ist das in deinem Beispiel die abstrakte Klasse? Vielen Dank. –

+0

@TylerPantuso: 'AbstractConclusion' ist nur eine Basisklasse, um alle ähnlichen Funktionalitäten von Conclusion zu gruppieren, so dass Sie nicht für alle untergeordneten Klassen neu schreiben müssen. Für den zweiten Teil Ihrer Frage sollte es alle Typen akzeptieren (um primitiv, int und IConcluable zu unterstützen). –

+0

Müsste "IConcludable" nicht vollständig entfernt werden? –

0

Mit where T : IConcludable generischen Typ Einschränkung können Sie int nicht als generisches Argument übergeben. Außerdem gibt es keine Möglichkeit, eine Schnittstelle an den primitiven Typ anzuhängen.

Sie können dies umgehen. Sie können die Hauptlogik von Conclusion in Basis abstrakte Klasse gesetzt und erben von ihm, restrukturieren Conclusion als class (weil struct s nicht Vererbung) und erstellen Klassen

public class Conclusion<T> : BaseConclusion 
where T : IConcludable 

und

public class PrimitiveConclusion<T> : BaseConclusion 
where T : struct 

und auch Sie sollte eine andere Klasse für string erstellen, wie string ist nicht struct und nicht zu implementieren IConcludable

Wie ich weiß, da ich Es gibt keine andere Möglichkeit, verschiedene Typen als generische Argumente zu übergeben.


Auch statt der Schaffung Conclusion Klasse für integrierte Typen Sie Wrapper-Struktur zu schaffen, die IConcludable umsetzen. Und haben einen Deal mit ihm

public struct Wrapper<T> : IConcludable 
{ 
    public T Value { get; set; } 
} 
Verwandte Themen