Laden...

[gelöst] Art typeof für Namen von Variablen gesucht

Erstellt von mosspower vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.485 Views
mosspower Themenstarter:in
456 Beiträge seit 2007
vor 15 Jahren
[gelöst] Art typeof für Namen von Variablen gesucht

Hallo "Kollegen",

ist es möglich für Variablennamen einen Ausdruck zu verwenden, so dass beim Refactoring Anpassungen sofort mit durchgeführt werden.

Zum Beispiel kann man das ja bei Klassen so machen ...

String className = typeof(TestClass).FullName;

Gibt es da auch eine Möglichkeit für Variablen? Hintergrund ist der, dass ich für verschiedene Instanzvariablen in einer Interfacemethode zur Serialisierung anmelden möchte. Gegenwärtig habe ich das so gelöst, dass man eine Set und Get-Methode überschreibt und hier den Namen der Variablen (als String) und den Wert (als Object) in ein Dictionary-Objekt packt.

Jetzt dachte ich, dass das einfacher gehen soll und ohne Variablennamen als String. Ich dachte an eine Methode IList<???Identifier??, Object> GetSerializableVariables nur welchen Identifier nehme ich hier.

Gibt es eine andere Möglichkeit, z.B. int, String, double ect. überladen und neuen Typ, z.B. SerializableInt, SerializableString zuweisen und mittels Reflektion werden dann diese Typen nach dem Instanzieren manipuliert?

Wie löst ihr das?

Danke schon mal für etwaige Antworten im Voraus?

5.941 Beiträge seit 2005
vor 15 Jahren

Hallo mosspower

Nein das geht nicht.
Wieso dekorierst du deine Eigenschaften nicht einfach mit Attributen?
Dann ist eine Namensänderung egal.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 15 Jahren

Hallo Peter Bucher,

das mit den Attributen ist eine super Idee, vielen Dank. Jetzt muss ich nur noch mal gucken ob das mit privaten Instanzvariablen auch geht und dann mittels Reflection bei der Instanzierung die serialisierten Werte setzen. 👍

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 15 Jahren

Es geht mit ...


[AttributeUsage(AttributeTargets.Field)]
  class SerializableField : Attribute {
    
  }

braucht man da eigentlich ein eigenes Attribut oder kann man da vordefinierte (welche?) verwenden?

5.941 Beiträge seit 2005
vor 15 Jahren

Salute mosspower

braucht man da eigentlich ein eigenes Attribut oder kann man da vordefinierte (welche?) verwenden?

Ich würde ein eigenes dafür schreiben.
Es gibt zwar schon festgelegte, allerdings werden die vom .NET Framework selber benutzt.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 15 Jahren

Hallo Peter Bucher,

vielen Dank nochmal für Deinen Hint. Codeeinsparung > 95 Prozent 😁 👍

5.941 Beiträge seit 2005
vor 15 Jahren

Hallo mosspower

Kein Problem.
Wie sieht der Code den jetzt bei dir aus?

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 15 Jahren

Naja, ich benutze das Attribute ...


 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
  class SerializableField : Attribute {
    
  }

und im Code dann benutze ich die halt mit Attributes ... z.B. ...


  [SerializableField]
    private int blub = 0;

    [SerializableField]
    private String bla = String.Empty;

    private Decimal nonSerializable = 0.0m;

Wird die Applikation runtergefahren, dann werden alle mit Attribut geflagten Fields und Properties mittels Reflektion serialisiert, beim Start werden dann die Werte gesetzt (wenn vorhanden), nach Instanzierung mittels Reflektion.

M
1.439 Beiträge seit 2005
vor 15 Jahren

Warum verwendest du nicht die Attribute Serializable und NonSerialized und die Standardserialisierung von .Net?

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo mosspower,

an die Namen von Feldern kommst du quasi genauso einfach wie an den Namen der Klasse. Stichwort: MemberInfo, FieldInfo.

herbivore

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 15 Jahren

Hallo herbivore,

da hast Du recht, nur ist hier das Problem, dass ich einen String brauche um Operationen anzustellen, z.B. wenn Field name ist bla (wobei bla ein String ist, der soz. ein Verweis auf die Variable ist), dann mache das ... usw. ... das braucht man bei Klassen nicht (hier kann man ja Klassentypen vergleichen, bzw. abfragen). Die einzige Lösung, die mir eingefallen wäre (ohne die Attribute, die sind die beste Lösung) wäre gewesen, dass ich allen relevanten Variablen ein Postfix-Flag anhänge, z.B.


private int myTestVariable_ser;

.. dann hätti ich mit FieldInfos nur die mit dem Postfix serialisiert.

Gruß

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 15 Jahren

Warum verwendest du nicht die Attribute Serializable und NonSerialized und die Standardserialisierung von .Net?

Weil man das Attribute nicht bei Felder verwenden kann. Ich möchte nicht das ganze Objekt serialisieren, da es sehr viele und sehr große sind. Es geht hier um Teilservices innerhalb eines Services (also zig Threads), die z.B. Imports, Counter, Fehler, Warnings etc. hochzählen und diese möchte ich nicht verlieren, wenn ich den Service runterfahre. Denn dann würde ich ja z.B. wieder bei 0 anfangen wenn aber z.B. schon X Dateien importiert worden sind an diesem Tag.

3.971 Beiträge seit 2006
vor 15 Jahren

Felder werden mitserialisiert. Beim XmlSerializer allerdings nur public Felder. Binäre und Soap-Formatierung verwenden beispielsweise nur Felder zur Serialisierung, egal ob public oder private.

Wenn du dir eine benutzerdefinierte Serialisierung einer Klasse wünschst, dann implementier das Interface IXmlSerializable oder ISerializable.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 15 Jahren

Hallo kleines_eichhoernchen,

ja, das hätte ich machen können, nur ist mir das im Moment zuviel Overhead, da es idR zwei bis drei Instanzvariablen sind (normaler Typ, also String oder int). Ich habe ja gegenwärtig schon eine lauffähige Lösung, ist auch so eine Art Anpassung an das Objekt, aber das erschien mir zu aufwändig, irgendwie wie mit Kanonen auf Spatzen schießen. Ich denke, dass die Lösung mit Attributes eine saubere (nicht die sauberste) und schnellste Lösung ist.

1.665 Beiträge seit 2006
vor 15 Jahren

Noch ein kleiner Hinweis:
Setze 'Attribute' hinter dem Attribut-Klassennamen. Damit folgst der Namenskonvention für Attribute.

M
1.439 Beiträge seit 2005
vor 15 Jahren

Warum verwendest du nicht die Attribute Serializable und NonSerialized und die Standardserialisierung von .Net?

Weil man das Attribute nicht bei Felder verwenden kann...

Das NonSerialized Attribute kann man doch gerade nur bei Feldern verwenden!?

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 15 Jahren

Hier ist noch der Code .. habe ich in meine Serializable-Utilityklasse gepackt ...


using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using Util;
using System.Runtime.Serialization;
using System.Reflection;

namespace Util {
  /// <summary>
  /// Handles serialization issues
  /// </summary>
  public class SerializationUtil {
    private static readonly String PREFIX_SERIALIZABLE_VALUES_FIELD = "F_";
    private static readonly String PREFIX_SERIALIZABLE_VALUES_PROPERTY = "P_";
    private static readonly BindingFlags SERIALIZABLE_VALUES_BINDINGFLAGS = 
      BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;

    /// <summary>
    /// Sets all fields and properties which are flagged with the 
    /// <see cref="Util.SerializableValue"/> attribute on the passed instance
    /// </summary>
    /// <param name="instance">The instance</param>
    /// <param name="serializedValues"></param>
    public static void SetSerializableValues(Object instance, Dictionary<String, Object> serializedValues) {
      try {
        // Check instance
        if(instance == null) {
          throw new ArgumentException("Parameter instance was passed null");
        }

        // Check serialized values
        if(serializedValues == null) {
          throw new ArgumentException("Parameter serializedValues was passed null");
        }

        foreach(String key in serializedValues.Keys) {
          String removePrefix = String.Empty;

          if(key.StartsWith(SerializationUtil.PREFIX_SERIALIZABLE_VALUES_FIELD)) {
            String fieldName = StringUtil.ReplaceEmpty(key, 
              SerializationUtil.PREFIX_SERIALIZABLE_VALUES_FIELD);

            // Get field info
            FieldInfo fieldInfo = instance.GetType().GetField(fieldName,
              SerializationUtil.SERIALIZABLE_VALUES_BINDINGFLAGS | BindingFlags.GetField);

            // Set value
            fieldInfo.SetValue(instance, serializedValues[key]);
          }
          else if(key.StartsWith(SerializationUtil.PREFIX_SERIALIZABLE_VALUES_PROPERTY)) {
            String fieldName = StringUtil.ReplaceEmpty(key,
            SerializationUtil.PREFIX_SERIALIZABLE_VALUES_PROPERTY);

            // Get property info
            PropertyInfo propertyInfo = instance.GetType().GetProperty(fieldName,
              SerializationUtil.SERIALIZABLE_VALUES_BINDINGFLAGS | BindingFlags.GetProperty);

            // Set value
            propertyInfo.SetValue(instance, serializedValues[key], null);
          }
        }
      }
      catch {
        throw;
      }
    }

    /// <summary>
    /// Gets all instance field and property values for the passed instance
    /// which has been flagged with the attribute <see cref="Util.SerializableValue"/>
    /// </summary>
    /// <param name="instance">The instance</param>
    /// <returns>Dict</returns>
    public static Dictionary<String, Object> GetSerializableValues(Object instance) {
      Dictionary<String, Object> serializableValues = null;

      try {
        if(instance != null) {
          // Get all field infos
          FieldInfo[] fieldInfos = instance.GetType().GetFields(
            SerializationUtil.SERIALIZABLE_VALUES_BINDINGFLAGS | BindingFlags.GetField);

          if(fieldInfos != null) {
            foreach(FieldInfo fieldInfo in fieldInfos) {
              Object[] customAttributes = fieldInfo.GetCustomAttributes(true);

              if(customAttributes != null) {
                foreach(Object customAttribute in customAttributes) {
                  if(customAttribute.GetType().Equals(typeof(SerializableValue))) {
                    // Add to dictionary
                    if(serializableValues == null) {
                      serializableValues = new Dictionary<String, Object>();
                    }

                    serializableValues.Add(SerializationUtil.PREFIX_SERIALIZABLE_VALUES_FIELD +
                      fieldInfo.Name, fieldInfo.GetValue(instance));
                  }
                }
              }
            }
          }

          // Get all property infos
          PropertyInfo[] propertyInfos = instance.GetType().GetProperties(
            SerializationUtil.SERIALIZABLE_VALUES_BINDINGFLAGS | BindingFlags.GetProperty);

          if(propertyInfos != null) {
            foreach(PropertyInfo propertyInfo in propertyInfos) {
              Object[] customAttributes = propertyInfo.GetCustomAttributes(true);

              if(customAttributes != null) {
                foreach(Object customAttribute in customAttributes) {
                  if(customAttribute.GetType().Equals(typeof(SerializableValue))) {
                    // Add to dictionary
                    if(serializableValues == null) {
                      serializableValues = new Dictionary<String, Object>();
                    }

                    serializableValues.Add(SerializationUtil.PREFIX_SERIALIZABLE_VALUES_PROPERTY +
                      propertyInfo.Name, propertyInfo.GetValue(instance, null));
                  }
                }
              }
            }
          }
        }
      }
      catch {
        throw;
      }

      return serializableValues;
    }
  }
}