Properties vor null Zuweisung schützen


  • Administrator

    Hallo zusammen,

    Kurzes Code-Beispiel:

    public class MyClass
    {
      public string Name { get; set; }
    }
    

    Wie kann ich am einfachsten Name davor schützen, dass jemand null zuweisst. Das einzige was ich kenne ist:

    public class MyClass
    {
      private string m_name;
    
      public string Name
      {
        get { return m_name; }
        set { m_name = (value != null ? value : "" /* oder throw oder was auch immer */); }
      }
    }
    

    Gibt es da keine einfachere Lösung? Mir geht es langsam auf den Nerv, dass ich nur wegen null immer wieder diesen Code schreiben muss. Inzwischen ist er sogar schon als Snippet vorhanden. Die ganze Zeit muss man auf null prüfen ...

    Grüssli



  • Mach den Setter doch einfach private und erlaube nur eine einmale zuweisung über den ctor und dort prüfst du auf null und fertig.



  • Du kannst auch den geheimoperator nutzen 😛

    public class MyClass
    {
      private string m_name;
    
      public string Name
      {
        get { return m_name; }
        set { m_name = value ?? string.Empty; }
      }
    }
    

    wäre das einfachste was mir grad einfällt wenn der setter unbedingt public sein muss.sorry für den doppelpost



  • Hilft vllt ein null-Value_objekt? Dann entfällt zumindest die Prüfiung.
    http://de.wikipedia.org/wiki/Nullobjekt_(Entwurfsmuster)



  • Die Grundfrage die ich mir gestellt habe ist doch eher, warum du die Logik der Null-Prüfung unbedingt im Setter haben musst. Ich meine wenn jemand mit dem objekt arbeitet dann soll der sich gefälligst drum kümmern das da kein Null Zugewiesen wird, so ist es zumindest meine Erwartung.



  • Wie wäre es mit dieser Idee?

    public static class PropertySetter
    {
        public static string Set(string value)
        {
            if (value == null)
            {
                var propertyName = new StackFrame(1).GetMethod().Name;
                throw new ArgumentNullException(string.Format("The property {0} is empty", propertyName.Substring(4)));
            }
            return value;
        }
    }
    
    public class MyClass 
    {
        private string m_name; 
    
        public string Name 
        {
            get { return m_name; }
            set { m_name = PropertySetter.Set(value); }
        }
    }
    

    So sparst du dir Code Duplikation im sinne des DRY


  • Administrator

    Firefighter schrieb:

    Mach den Setter doch einfach private und erlaube nur eine einmale zuweisung über den ctor und dort prüfst du auf null und fertig.

    Und was ist, wenn du den Namen des Objektes ändern möchtest? MyClass hat natürlich noch andere Eigenschaften, Methoden, usw. usf. Falls das nicht klar war 🙂

    Firefighter schrieb:

    Du kannst auch den geheimoperator nutzen 😛

    Den hatte ich tatsächlich ganz vergessen, danke für die Erinnerung. Er heisst übrigens nicht "Geheimoperator" sondern Null-coalescing Operator. Wobei ich allerdings zustimmen muss, dass Geheimoperator besser klingt und einfacher auszusprechen ist 😃

    Firefighter schrieb:

    Die Grundfrage die ich mir gestellt habe ist doch eher, warum du die Logik der Null-Prüfung unbedingt im Setter haben musst. Ich meine wenn jemand mit dem objekt arbeitet dann soll der sich gefälligst drum kümmern das da kein Null Zugewiesen wird, so ist es zumindest meine Erwartung.

    Jein. Es gibt auch das Problem, wenn das Objekt weiterverwendet wird. Dann muss man überall auch ausserhalb eine Prüfung auf null machen, obwohl null vielleicht einfach nur ein bescheuerter Wert ist. Man könnte natürlich dies alles in die Dokumentation schreiben und einfach auf eine NullReferenceException setzen. Und sagen: "Selber schuld, wenn du den Wert auf null setzt". Aber klingt für mich nicht nach einer guten Idee. Zudem tritt die NullReferenceException oder plötzliche ArgumentNullException bei der Übergabe an eine andere API, an einer völlig anderen Stelle auf, als dort wo der tatsächliche Fehler gemacht wurde.

    witte schrieb:

    Hilft vllt ein null-Value_objekt? Dann entfällt zumindest die Prüfiung.
    http://de.wikipedia.org/wiki/Nullobjekt_(Entwurfsmuster)

    Und wie soll man dies hier nun einsetzen? Ich möchte vielleicht hier nochmals darauf hinweisen, falls das wirklich nicht klar gewesen sein sollte:
    MyClass hat natürlich noch andere Eigenschaften, Methoden, usw. usf. Ein Nullobjekt von MyClass und einem privaten Setter für Name geht nicht.

    @CSL,
    Ja, so verhindert man einen Teil der Codeduplizierung, daran habe ich auch schon gedacht. Extramember gibt es trotzdem noch und der Getter ist auch immer gleich. Man hat immer noch eine dämliche Dupplizierung 🙂
    Zudem würde ich keine Reflections einsetzen, sondern der Methode Set einen zweiten Parameter übergeben.

    Noch eine weitere ähnliche Möglichkeit wäre dies hier:

    public struct Property<ValueT>
      where ValueT : class
    {
      private ValueT m_value;
    
      public Property(ValueT v)
      {
        m_value = v;
      }
    
      public static implicit operator ValueT(Property<ValueT> v)
      {
        return v.m_value;
      }
    
      public static implicit operator Property<ValueT>(ValueT v)
      {
        if(v == null)
        {
          throw new ArgumentNullException("value");
        }
    
        return new Property<ValueT>(v);
      }
    }
    
    public class MyClass
    {
      public Property<string> Name { get; set; }
    }
    

    Man könnte dann immer noch null zuweisen, indem man ein new Property<string>() zueweist, aber das würde dann schon fast mit böswilliger Absicht geschehen. Wirklich schön empfinde ich es aber auch nicht.

    Grüssli



  • Also ich deine Lösung schick, was gefällt dir daran nicht?

    Was die Duplikation an geht, das Problem hat man mit den "PropertyChanged" Strings für WPF auch.
    http://www.mycsharp.de/wbb2/thread.php?threadid=80535
    Mit Attribute ist da noch viel raus zu holen, aber trotzdem ist es dort leider unvermeidliche Duplikation. Man kann es maximal noch durch viel Overhead und Performance Einbußen schaffen => http://www.codeproject.com/KB/cs/NotifyingAttribute.aspx


  • Administrator

    CSL schrieb:

    Also ich deine Lösung schick, was gefällt dir daran nicht?

    Es wirkt so gefrickelt, es riecht so nach Workaround. Ich weiss nicht. Wahrscheinlich würde ich mich erst mit einem nonnull Keyword der Sprache selbst zufrieden geben ...

    Zudem habe ich gerade entdeckt, dass ich noch ein Problem habe. Und zwar:

    class MyClass<ValueT>
    {
      public ValueT Value { get; set; }
    
      // usw.
    }
    
    // ...
    
    var mv = new MyClass<int>();
    mv.Value = 10;
    
    var mr = new MyClass<string>();
    mr.Value = null; // <- soll verhindert werden.
    

    Bisschen schwer, wenn ich mich nicht auf Referenztypen einschränken möchte beim Generic-Typ. Ach, ich vermisse meine Templates aus C++ 😃

    Grüssli


Anmelden zum Antworten