Generische Eigenschaft erstellen

74

Ich habe eine Klasse, die einen serialisierten Wert und einen Typ speichert. Ich möchte, dass eine Eigenschaft / Methode den bereits gegossenen Wert zurückgibt:

public String Value { get; set; }

public Type TheType { get; set; }

public typeof(TheType) CastedValue { get { return Convert.ChangeType(Value, typeof(_Type)); }

Ist das in C # möglich?

EBarr
quelle
4
Generische Eigenschaften wären schön; Ich denke, es var val = obj.Prop<Type>ist prägnanter für eine typbasierte Suche als obj.Prop[typeof(Type)]oder obj.GetProp<Type>().
Dan Lugg

Antworten:

106

Es ist möglich, wenn die Klasse, die die Eigenschaft enthält, generisch ist und Sie die Eigenschaft mit dem generischen Parameter deklarieren:

class Foo<TValue> {
    public string Value { get; set; }
    public TValue TypedValue {
        get {
            return (TValue)Convert.ChangeType(Value, typeof(TValue));
        }
    }
}

Eine Alternative wäre, stattdessen eine generische Methode zu verwenden:

class Foo {
    public string Value { get; set; }
    public Type TheType { get; set; }

    public T CastValue<T>() {
         return (T)Convert.ChangeType(Value, typeof(T));
    }
}

Sie können die System.ComponentModel.TypeConverterKlassen auch zum Konvertieren verwenden, da sie es einer Klasse ermöglichen, ihren eigenen Konverter zu definieren.

Bearbeiten : Beachten Sie, dass Sie beim Aufrufen der generischen Methode den generischen Typparameter angeben müssen, da der Compiler keine Möglichkeit hat, darauf zu schließen:

Foo foo = new Foo();
foo.Value = "100";
foo.Type = typeof(int);

int c = foo.CastValue<int>();

Sie müssen den Typ beim Kompilieren kennen. Wenn Sie den Typ zur Kompilierungszeit nicht kennen, müssen Sie ihn in einem speichern object. In diesem Fall können Sie der FooKlasse die folgende Eigenschaft hinzufügen :

public object ConvertedValue {
    get {
        return Convert.ChangeType(Value, Type);
    }
}
Brannon
quelle
Im zweiten Beispiel der Klasse 'Foo bin ich verblüfft: eine öffentliche Eigenschaft' theType wird deklariert: "public Type TheType {get; set;}", scheint aber im Code nicht verwendet zu werden. danke,
BillW
Die Eigenschaft war im ursprünglichen Beispiel. Ich habe es gerade gelassen.
Brannon
Wenn ich die Brannons-Lösung ausprobiere, wird ein Laufzeitfehler angezeigt, der besagt, dass das Objekt, das ich gieße, IConvertible implementieren muss. Habe ich etwas falsch gemacht, weil dies wie ein Deal Breaker erscheint, es sei denn, ich habe eine Klasse besetzt, in der ich die Quelle zur Verfügung habe.
Keith
59

Eigenschaften, Ereignisse, Konstruktoren usw. können nicht generisch sein - nur Methoden und Typen können generisch sein. Meistens ist das kein Problem, aber ich stimme zu, dass es manchmal ein Schmerz ist. Brannons Antwort gibt zwei vernünftige Problemumgehungen.

Jon Skeet
quelle
5

Ich glaube nicht, dass das Beispiel, das Sie hier gegeben haben, möglich ist. Der Typ von CastedValue muss zur Kompilierungszeit definiert werden. Dies bedeutet, dass er nicht von einem Laufzeitwert (dem Wert der TheType-Eigenschaft) abhängen kann.

BEARBEITEN: Brannons Lösung enthält einige gute Ideen, wie dies mithilfe einer generischen Funktion anstelle einer Eigenschaft gehandhabt werden kann.

Charlie
quelle