Properties vor null Zuweisung schützen
-
Hallo zusammen,
Kurzes Code-Beispiel:
public class MyClass { public string Name { get; set; } }
Wie kann ich am einfachsten
Name
davor schützen, dass jemandnull
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 aufnull
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
-
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 warFirefighter 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, obwohlnull
vielleicht einfach nur ein bescheuerter Wert ist. Man könnte natürlich dies alles in die Dokumentation schreiben und einfach auf eineNullReferenceException
setzen. Und sagen: "Selber schuld, wenn du den Wert auf null setzt". Aber klingt für mich nicht nach einer guten Idee. Zudem tritt dieNullReferenceException
oder plötzlicheArgumentNullException
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 vonMyClass
und einem privaten Setter fürName
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 MethodeSet
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 einnew 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
-
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