Laden...

Propertys dynamisch setzen?

Erstellt von Briefkasten vor 14 Jahren Letzter Beitrag vor 14 Jahren 869 Views
Briefkasten Themenstarter:in
446 Beiträge seit 2004
vor 14 Jahren
Propertys dynamisch setzen?

Hallo,

ich habe folgendes Event von einem Remotingdienst in einer GUI Anwendung abonniert (Wird von einem Windowsdienst ausgelöst). Immer wenn sich eine Property vom WindowsDienst ändert löst er ein Event aus, in dem drinnen steht:

1.) Welches Property hat sich geändert ( also den PropertyName
2.) Der Neue Wert der Property

protected void RemoteServiceEvents_OnHostToClient(object sender, RemotePropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "IsSyncing":
                    IsSyncing = (bool)e.PropertyValue;
                    break;
                case "LastCopiedFile":
                    LastCopiedFile = e.PropertyValue.ToString();
                    break;
                case "Topic":
                    Topic = e.PropertyValue.ToString();
                    break;
                default:
                    System.Diagnostics.Debug.WriteLine("unknown propertyname");
                    break;
            }

            LastCopiedFile = e.PropertyValue.ToString();
        }

Das Objekt RemotePropertyChangedEventArgs
beinhaltet:

        private readonly string _PropertyName;
        private readonly object _PropertyValue;

Jetzt muss ich wie ihr oben seht, das ganze hardcodiert den einzelnen Propertys zuweisen.

Ich hätte auch ein Interface zu verfügung. Also ich weiß genau, wie die Propertys heißen können/ von welchem Typ sie sind die ich über RemotePropertyChangedEventArgs erhalten könnte.

Hat jemand eine Idee, wie ich das ohne switch Anweisung gebacken bekomme. Am besten dynamisch, dass ich flexibel bleiben kann.

Momentan fällt mir nur der umständliche Weg über Reflection ein. Oder gibts da noch eine bessere Lösung?

Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo Briefkasten,

PropertyInfo.SetValue

herbivore

T
210 Beiträge seit 2006
vor 14 Jahren

Hallo Briefkasten,

das dynamischste ist Reflection, wie herbivore schon vorschlug. Wenn Du auf Reflection verzichten möchtest, kannst Du alternativ zur switch-Anweisung ein Dictionary benutzen:


        class MyClass
        {
            bool IsSyncing { get; set; }
            string LastCopiedFile { get; set; }

            protected void RemoteServiceEvents_OnHostToClient(object sender, RemotePropertyChangedEventArgs e)
            {
                SetProperty setter;
                if (PropertySetter.TryGetValue(e.PropertyName, out setter))
                    setter(this, e.PropertyValue);
                else
                    System.Diagnostics.Debug.WriteLine("unknown propertyname");
            }

            private delegate void SetProperty(MyClass instance, object value);
            private static readonly Dictionary<string, SetProperty> PropertySetter = new Dictionary<string, SetProperty>
            {
                { "IsSyncing", (inst, v) => inst.IsSyncing = (bool)v },
                { "LastCopiedFile", (inst, v) => inst.LastCopiedFile = (string)v },
            };
        }


Das Dictionary musst Du dann halt pflegen...

Gruß
T-Man

5.299 Beiträge seit 2008
vor 14 Jahren

und in Kombination könnte man zur Initialisierung mit Reflection ein Dictionary<string, PropertyInfo> aufbauen, was im Weiteren genutzt wird.

Der frühe Apfel fängt den Wurm.

Briefkasten Themenstarter:in
446 Beiträge seit 2004
vor 14 Jahren

Hallo,

danke für euere Antworten. Ich werde das so umsetzen wie T-Man und ErfinderDesRades vorgeschlagen haben.

Statt der Instanz werde ich aber das Interface verwenden. Das müsste auch gehen.

Evtl. werde ich auch den delegate Dynamisch erzeugen, damit man jedes beliebige Interface beim SetProperty verwenden kann.

Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp

5.299 Beiträge seit 2008
vor 14 Jahren

einen eigenen Delegaten kannstedir ühaupt sparen. Nimm Action<T, object>

edit: wobei, wenndes dynamisch über PropertyInfos machst, diede reflectionmäßig aus dem Interface ausliest - da braucht man doch gar keinen Delegaten.
Da bekommt man doch ein Dictionary<string, PropertyInfo>, und PropertyInfo.SetValue() ist doch bei jedem Interface gleich.

Der frühe Apfel fängt den Wurm.

Briefkasten Themenstarter:in
446 Beiträge seit 2004
vor 14 Jahren

Hallo,

ich hab das jetzt so gemacht:

public class PropertySetterHelper
        {
            public PropertySetterHelper(object pInstance)
            {
                if (pInstance == null)
                    throw new ArgumentException("Cant be null pInstance");

                _Instance = pInstance;
            }

            public void SetProperty(string pPropertyName, object PropertyValue)
            {
                Type type = _Instance.GetType();

                PropertyInfo propertyInfo = type.GetProperties().ToList().Where(a => a.Name.Equals(pPropertyName)).First();
if(propertyInfo ==null) return;
                propertyInfo.SetValue(_Instance, PropertyValue, null);
            }

            private readonly object _Instance = null;

        }

Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp

5.299 Beiträge seit 2008
vor 14 Jahren

hier ne generische Variante mit statischem Dictionary:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace _Tests {
   public class PropertySetterHelper<T>where T:class {

      private static Dictionary<string, PropertyInfo> _Props = new Dictionary<string, PropertyInfo>();

      private readonly T _Instance = null;

      static PropertySetterHelper() {
         foreach(var pi in typeof(T).GetProperties()) {
            _Props.Add(pi.Name, pi);
         }
      }

      public PropertySetterHelper(T pInstance) {
         if(pInstance == null) throw new ArgumentNullException("pInstance");
         _Instance = pInstance;
      }

      public void SetProperty(string pPropertyName, object PropertyValue) {
         _Props[pPropertyName].SetValue(_Instance, PropertyValue, null); 
      }

   }
}


Das Auslesen der PropertyInfos erfolgt nur einmalig beim Instanzieren des ersten Instanz.
Weil im statischen Konstruktor.
Und alle Instanzen verwenden dasselbe Dictionary.

Der frühe Apfel fängt den Wurm.