2010-01-05 6 views
5

Hey, ich denke, ich habe hier die falsche Vorstellung, aber ich bin mir nicht sicher, was das Beste ist. Ich möchte eine Klasse mit einer Mitgliedsvariablen, die von jedem Typ sein kann, abhängig davon, was zu der Zeit benötigt wird. Bisher habe ich so etwas wie diese:Generische Klassenmitglieder in C#?

public class ConfigSetting<T> { 
    private T value; 

    public T GetValue() { 
     return value; 
    } 
    public void ChangeValue() { 

    } 

    public ConfigSetting(string heading, string key) { 
     this.value = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
    } 
} 

Der Typ von der rechten Seite der ‚this.value‘ Leitung zurück ist eine Zeichenfolge, die derzeit. Ich weiß, hier scheint es, als ob ich nichts anderes als den Stringtyp verwenden müsste, aber irgendwann werde ich den Konstruktor erweitern, so dass "this.value" ein String, int, float oder bool sein kann.

Wie auch immer, mein Compiler sagt "Kann 'String' nicht in 'T' umwandeln, also nehme ich an, dass ich etwas sehr rückwärts mache.

Vielen Dank.

Antwort

6

Nun, was für Konvertierung haben Sie es erwarten bewerben? Wenn Sie den Wert bereits sein von der richtigen Art erwarten, könnten Sie tun:

object tmp = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
this.value = (T) tmp; 

Beachten Sie, dass durch object gehen entweder implizit (wie hier) oder mit einer expliziten Besetzung:

this.value = (T)(object) DerivedMethods.configsettings... (etc); 

Die Anzahl der für generische Typen bereitgestellten Konvertierungen ist etwas begrenzt. Aber es sollte funktionieren, wenn der ursprüngliche Wert wirklich korrekt ist.

+1

Danke. Dies kompiliert (obwohl ich es noch testen muss). Ich habe zwei Fragen: 1: Warum muss ich durch Objekt gehen? 2: Was passiert danach, wenn ich versuche, String-Methoden auf Wert zu verwenden? Weiß C# nun, dass der Wert vom Typ String ist? – Xenoprimate

+1

gibt RawValue nicht immer eine Zeichenkette zurück? würde die Konvertierung nach int, long usw. nicht fehlschlagen? – bendewey

+0

Ja, aber wie ich in meiner ursprünglichen Frage gesagt habe, möchte ich den Konstruktor erweitern. – Xenoprimate

2

Sie müssen die zurück String T würfen

public ConfigSetting(string heading, string key) { 
    this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
} 
+0

Dies funktioniert nicht, der gleiche Fehler. Ich hätte gesagt, dass ich das bereits versucht habe, aber ich vermutete, dass das Problem tiefer war. – Xenoprimate

0

Es sieht so aus, als ob Sie dem generischen Element eine Zeichenfolge (configsettings.SettingGroups[heading].Settings[key].RawValue) zuweisen möchten. Sie müssen eine Möglichkeit bereitstellen, um die Zeichenfolge in Typ T zu konvertieren - normalerweise durch Casting. Zum Beispiel:

this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
0

In dieser Zeile:

this.value = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 

Sie setzen Ihre Variable vom Typ T auf einen String-Wert. Die RawValue-Methode gibt eine Zeichenfolge zurück. Sie müssen es explizit in den Typ T umwandeln.

this.value = (T) (object) DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 

Wird es wirklich nur Werte ohne Konstrukteure geben? Sie können dies explizit machen und vermeiden das Objekt Gießen, wenn Sie das aus irgendeinem Grund vermeiden wollen.

1

Ich denke, Sie sollten nicht unbedingt Generika verwenden, um vorausschauend für alle möglichen zukünftigen Szenarien zu planen, weil Sie wahrscheinlich in Randfälle in der Zukunft stoßen und den Code unabhängig ändern müssen.

Wenn Sie jedoch bereits mehrere Szenarien haben, zu denen ein Generic passen würde, können Sie jetzt von der Wiederverwendung der Logik profitieren und sie alle richtig testen.

Ich sehe andere haben bereits Code-Antworten zur Verfügung gestellt, damit ich hier aufhören werde.

1

Ich gehe davon aus, dass

DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue 

eine Zeichenfolge ist.

Sie können keine Zeichenfolge zu this.value zuweisen, da der Typ this.valueT ist und alles sein könnte, z. B. Typen, denen Strings nicht zuweisbar sind.

Eine Lösung besteht darin, den generischen Parameter zu entfernen und value eine Zeichenkette zu machen, und dann verschiedene Arten des Zugriffs anzugeben, die Boole, Floats oder was auch immer wie benötigt parsen.

public float GetFloatValue { 
    get { return float.Parse(this.value); } 
} 

// etc 
0

eine

string strValue = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
this.value = (T)Convert.ChangeType(strValue, typeof(T), CultureInfo.InvariantCulture) 

Versuchen Sie, wenn Sie Ihre Konfigurationswerte als Strings gespeichert haben und wollen, dass es in den richtigen Typ umgewandelt. Dies funktioniert nur für die meisten primitiven Typen wie Int32, Double usw.

7

Sie stoßen auf Probleme, weil dies keine gute Verwendung von Generika ist. Wenn der generische Typparameter nur auf vier verschiedene Arten konstruiert werden kann - string, float, bool und int - dann ist das nicht sehr generic. Ich erwarte, dass eine generische Sache sein kann jeder Art überhaupt.

Wenn ich eine Sache, die nur eine von vier Typen sein könnte, dann würde ich es wie folgt Modell:

abstract class ConfigSetting 
{ /* shared code here */ } 

class TextSetting : ConfigSetting 
{ /* Code here to handle string settings */ } 

class BooleanSetting : ConfigSetting 
{ /* ... 

und so weiter. Ich würde dann wahrscheinlich jedem von ihnen einen internen Konstruktor geben und die Basisklasse in eine Fabrik für die abgeleiteten Klassen unter Verwendung des Fabrikmusters machen.

Verwenden Sie nur Generika, wenn Ihre Lösung wirklich generisch ist. Wie List<T>, zum Beispiel, kann eine Liste von alles sein: Ints, Strings, Arrays, Wörterbücher, Funktionen, was auch immer. Wenn das Ding, das Sie modellieren, eine kleine Anzahl von möglichen Typen hat, machen Sie einfach einen für jeden Typ.