2016-03-19 5 views
2

ich Aufruf möchte:C# generische Klasse als Parameter mit dem gleichen T wie genannt Methode der allgemeinen Klasse

Question<Entity> question = 
    Question<Entity>.Create(
     Choice.Create(). 
      AddFollowUpQuestion(Question.Create()). 
      AddFollowUpQuestion(Question.Create()), 
     Choice.Create() 
    ); 

Aber das beste C# ermöglicht es mir zu tun:

Question<Entity> question = 
    Question<Entity>.Create(
     Choice<Entity>.Create(). 
      AddFollowUpQuestion(Question<Entity>.Create()). 
      AddFollowUpQuestion(Question<Entity>.Create()), 
     Choice<Entity>.Create() 
    ); 

ich versuche zu Reinigen Sie einige Code, im Grunde nur syntaktischen Zucker hinzufügen, so dass einige Definitionen, die ich machen viel einfacher zu lesen sind.

Sowohl Intelisense als auch der Compiler wissen, dass sie erwarten, dass der Parameter vom Typ Choice ist, da es sich um eine Methode der generischen Klasse handelt. Aber ich muss immer noch den Typ von T für das übergebene Argument eingeben.

ein bisschen abstrakt: Ich versuche, eine Top-Level-generic-Klasse zu erstellen, in dem alle Eigenschaften, die auch generische Typen sind die gleiche Art von T. unter Verwendung

Kann mir jemand helfen, dieses Rätsel zu lösen? Oder erkläre mir wenigstens, warum ich den gleichen Typ immer wieder tippen muss?

Simplified Klassendefinitionen:

public class Question<T> where T : Entity 
{ 
    public static Question<T> Create(params Choice<T>[] choices) 
    { 
     return new Question<T> 
     { 
      Choices = choices 
     }; 
    } 

    private Choice<T>[] Choices { get; set; } 
} 

public class Choice<T> where T : Entity 
{ 
    public static Choice<T> Create() 
    { 
     return new Choice<T>(); 
    } 

    public Choice<T> AddFollowUpQuestion(Question<T> followUpQuestion) 
    { 
     FollowUpQuestions.Add(followUpQuestion); 

     return this; 
    } 

    private static List<Question<T>> FollowUpQuestions { get; set; } 
} 

public abstract class Entity 
{ 

} 
+0

Was ist falsch mit derblinkenlight's Antwort? – nawfal

+0

Zu schnell Kumpel, es ist Wochenende;) Ich habe gerade im Kommentar zu seiner Antwort geantwortet. –

Antwort

1

C# kann die Methode ableiten, die Sie aufrufen möchten, basierend über den Typ eines Parameters, aber es kann nicht den Typ der Klasse, auf die eine Methode, die einen Parameter des erforderlichen Typs erzeugt, abgeleitet werden: Der "Typ Inferenz Magie" geht nur in eine Richtung.

Im Wesentlichen Sie den Compiler Choice.Create() Ausdruck zu geben und die Tatsache, dass das Ergebnis ein Verfahren Choice<Entity> erwartet übergeben wird, und bittet sie zu folgern, dass Choice ist eigentlich ein generischer Typ (trotz der Tatsache, dass es eine nicht sein kann generische Choice im System), und es hat eine Create() Methode, die Choice<T> zurückgibt. Obwohl der Compiler es möglicherweise tun könnte, wäre die Implementierung teuer und könnte möglicherweise eine bahnbrechende Änderung sein.

Sie können jedoch eine allgemeine Hilfsmethode machen, die die gleichen T zu mehreren Klassen, wie diese bieten würden:

static Question<T> MakeQuestion<T>() { 
    return Question<T>.Create(Choice<T>.Create()); 
} 

Jetzt können Sie

Question<Entity> question = MakeQuestion<Entity>(); 

aufrufe und die Typ-Parameter übergeben nur Einmal.

Edit: Was die aufwändigere Beispiel von Ihrem bearbeiten betrifft, so sollten Sie die API durch die Einführung einer Fabrik verkürzen können, die auf Entity generisch ist, und Sie lässt Fragen erstellen, Follow-ups usw.

class QuestionFactory<T> { 
    public Question<T> CreateQuestion() { 
     ... 
    } 
    public Choice<T> CreateChoice() { 
     ... 
    } 
} 

Jetzt können Sie dies tun:

var qf = new QuestionFactory<Entity>(); 
var question = qf.CreateQuestion(
    qf.CreateChoice(). 
     AddFollowUpQuestion(qf.CreateQuestion()). 
     AddFollowUpQuestion(qf.CreateQuestion()), 
    qf.CreateChoice() 
); 
+0

Danke für die Erklärung WARUM es nicht funktioniert. Da ich versuche, eine Möglichkeit zu schaffen, Fragen fließend mit Fragen zu erstellen ... (Ich habe das Codebeispiel im ersten Post aktualisiert, um das zu zeigen) Ich glaube nicht, dass das in einen Helfer passt. Ich fürchte, ich werde Ihre Antwort als Antwort markieren. Lass mich ein wenig darüber nachdenken;) –

+0

Obwohl nicht so zufriedenstellend, wie ich es erhofft hatte, scheint deine Erklärung korrekt zu sein und dein Vorschlag, eine Fabrik zu benutzen, würde das Problem für mich lösen. Vielen Dank! –

0

Eine gemeinsame Sache zu tun ist, nicht generische Klassen für die Factory-Methode zu erstellen:

public static class Question { 
    public static Question<T> Create<T>(Choice<T> choice) { 
     return Question<T>.Create(choice); 
    } 
} 

... 
Question<Entity> question = Question.Create(Choice<Entity>.Create()); 
+0

Danke, aber das ist genau umgekehrt. Idealerweise würde ich nur den Typ für T an der äußersten Frage angeben und C# magic das allen Methoden auf der ganzen Linie mitteilen. –

0

eine Möglichkeit ist Question.Create(), um nicht zu erwarten, eine Wahl zu ändern zur Verfügung gestellt werden, rath Er schafft die Wahl selbst.Es macht den Code ein wenig einfacher und Sie können Ihr Ziel erreichen.

public class Question<T> where T : Entity 
{ 
    public static Question<T> Create() 
    { 
     return new Question<T> 
     { 
      Choice = Choice<T>.Create() 
     }; 
    } 

    private Choice<T> Choice { get; set; } 
} 

public class Choice<T> where T : Entity 
{ 
    public static Choice<T> Create() 
    { 
     return new Choice<T>(); 
    } 
} 

public abstract class Entity 
{ 

} 

Je nach Kontext kann dies eine positive Veränderung als Aufgabe der Schaffung einer Wahl wird auf die Frage bewegt, können Sie mit anderen Worten abstrakt die Anrufer von Question.Create() von der Hektik der Schöpfung nach Wahl.

Auf der anderen Seite erhöht es die Kopplung von Frage und Auswahl. Welche davon bevorzugt wird, hängt vom Rest der Architektur ab.

Natürlich nahm ich an, dass T in Choice wirklich benötigt wird.

+0

Ich bekomme die Idee, aber ich fürchte, es wird in diesem Fall nicht funktionieren. Ich habe ein komplizierteres Beispiel im ersten Beitrag gemacht, das deutlicher zeigt, dass ich eine fließende Art und Weise entwickle, Entscheidungen zu treffen, die Folgefragen haben, die wiederum wiederum Entscheidungen treffen können ... –

Verwandte Themen