3 Stimmen

Den *Wert* einer benutzerdefinierten Eigenschaft einer Objektinstanz abrufen?

Mit .NET 4, C#

Sagen wir, ich habe Unterricht Info die die CustomTypeDescriptor . Eine Instanz der Klasse Info hat ein Wörterbuch von <string, object> Paare, die zur Laufzeit geladen werden.

Ich möchte in der Lage sein, die Wörterbuchschlüssel als Eigenschaften freizugeben (so dass jede Instanz von Info unterschiedliche Eigenschaften hat). Die Werte der Eigenschaften sollten die entsprechenden Werte des Wörterbuchs sein.

Ich bin dazu übergegangen, Eigenschaften freizulegen:

    public override PropertyDescriptorCollection GetProperties()
    {

        var orig = base.GetProperties();
        var newProps = dictionary.Select( kvp => 
                       TypeDescriptor.CreateProperty(
                           this.GetType(), 
                           kvp.key, 
                           typeof(string)));
        return new PropertyDescriptorCollection(
                   orig.Cast<PropertyDescriptor>()
                   .Concat(newProps)
                   .ToArray());
    }

Das Problem ist, wie erhalte ich ihre Werte?

var info = new Info(new Dictionary<string, object>{{"some_property", 5}};
var prop = TypeDescriptor.GetProperties(i_info)["some_property"];
var val = prop.GetValue(i_info); //should return 5

Die einzige Möglichkeit, die ich gefunden habe, um die Kontrolle zu erhalten, wenn prop.GetValue() aufgerufen wird, war die Aufhebung von GetPropertyOwner(PropertyDescriptor pd) aber so wie ich es verstehe, erwartet es, dass ich die Instanz eines anderen Typ die eine passende reale (kompilierte) Eigenschaft hat.

Ich möchte in der Lage sein, die eigentliche Implementierung der Eigenschaft selbst zu schreiben (für dieses Beispiel den Wert im Wörterbuch zurückgeben, dessen Schlüssel mit dem Eigenschaftsnamen übereinstimmt).

Ist dies möglich?

3voto

Konstantin Oznobihin Punkte 5094

Sie müssen Ihre eigene Implementierung der PropertyDescriptor Klasse mit Überschreibungen GetValue Methode. Anstelle von TypeDescriptor.CreateProperty verwenden Sie neue MyCoolPropertyDescriptor(dictionary, kvp.Key) oder wie.

Hier ein Beispiel, wie es umgesetzt werden kann:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace ConsoleApplication1
{
    internal sealed class MyCoolPropertyDescriptor : PropertyDescriptor
    {
        private Func<object, object> propertyGetter;
        private Action<object, object> propertySetter;

        public MyCoolPropertyDescriptor(
            string name,
            Func<object, object> propertyGetter,
            Action<object, object> propertySetter)
            : base(name, new Attribute[] {})
        {
            this.propertyGetter = propertyGetter;
            this.propertySetter = propertySetter;
        }

        public override bool CanResetValue(object component)
        {
            return true;
        }

        public override System.Type ComponentType
        {
            get { return typeof(object); }
        }

        public override object GetValue(object component)
        {
            return this.propertyGetter(component);
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override System.Type PropertyType
        {
            get { return typeof(object); }
        }

        public override void ResetValue(object component)
        {
            this.propertySetter(component, null);
        }

        public override void SetValue(object component, object value)
        {
            this.propertySetter(component, value);
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }

    public sealed class Info : CustomTypeDescriptor
    {
        IDictionary<string, object> properties;

        public Info(IDictionary<string, object> properties)
        {
            this.properties = properties;
        }

        public override PropertyDescriptorCollection GetProperties()
        {
            var orig = base.GetProperties();
            var newProps = this.properties
                .Select(kvp => new MyCoolPropertyDescriptor(
                    kvp.Key,
                    o => ((Info)o).properties[kvp.Key],
                    (o, v) => ((Info)o).properties[kvp.Key] = v));

            return new PropertyDescriptorCollection(orig
                .Cast<PropertyDescriptor>()
                .Concat(newProps)
                .ToArray());
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var info = new Info(new Dictionary<string, object>{{"some_property", 5}});
            var prop = TypeDescriptor.GetProperties(info)["some_property"];
            var val = prop.GetValue(info); //should return 5
            Console.WriteLine(val);
        }
    }
}

2voto

Enigmativity Punkte 104081

Mein Verständnis von CustomTypeDescriptor ist, dass es die Datenbindung ermöglicht, zusätzliche Eigenschaften, z. B. für ein Raster, die in der Klasse eigentlich nicht vorhanden sind, aufzudecken. Es ist nicht etwas, das die CLR erweitert, so dass Ihre tatsächliche Klasse die Eigenschaft offenbart.

Wenn Sie tatsächliche CLR-Eigenschaften wünschen, müssen Sie sich mit DynamicObject o ExpandoObject um die Art von Funktionalität zu erhalten, die Sie meiner Meinung nach suchen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X