| Autor |
Nachricht |
Dravere
Moderator
Benutzerprofil
Anmeldungsdatum: 13.06.2005
Beiträge: 7252
|
Dravere Moderator
11:15:04 31.08.2010 Titel: |
Properties vor null Zuweisung schützen |
Zitieren |
Hallo zusammen,
Kurzes Code-Beispiel:
| C# Code: | public class MyClass
{
public string Name { get; set; }
}
| |
| C# Code: | public class MyClass
{
public string Name { get; set; }
}
| |
| C# Code: | 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:
| C# Code: | 1 2 3 4 5 6 7 8 9 10 | 1 2 3 4 5 6 7 8 9 10 | 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 */); }
}
}
| |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 | 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 */); }
}
}
| |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 | 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 |
_________________ Danke für die Hilfe, Antwort oder Meinung!
C++: Std-Lib Referenz
C# .Net: MSDN kennt die Antwort
|
|
 |
Firefighter
Mitglied
Benutzerprofil
Anmeldungsdatum: 27.03.2007
Beiträge: 2726
|
Firefighter Mitglied
11:17:17 31.08.2010 Titel: |
|
Zitieren |
|
 |
Firefighter
Mitglied
Benutzerprofil
Anmeldungsdatum: 27.03.2007
Beiträge: 2726
|
Firefighter Mitglied
11:19:20 31.08.2010 Titel: |
|
Zitieren |
Du kannst auch den geheimoperator nutzen :P
| C# Code: | 1 2 3 4 5 6 7 8 9 10 | 1 2 3 4 5 6 7 8 9 10 | public class MyClass
{
private string m_name;
public string Name
{
get { return m_name; }
set { m_name = value ?? string.Empty; }
}
}
| |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 | public class MyClass
{
private string m_name;
public string Name
{
get { return m_name; }
set { m_name = value ?? string.Empty; }
}
}
| |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 | 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 |
_________________ Mein Blog
Clean-Code-Developer
Wie man richtig Fragen stellt
|
|
 |
witte
Mitglied
Benutzerprofil
Anmeldungsdatum: 08.01.2008
Beiträge: 1295
|
witte Mitglied
11:26:45 31.08.2010 Titel: |
|
Zitieren |
|
 |
Firefighter
Mitglied
Benutzerprofil
Anmeldungsdatum: 27.03.2007
Beiträge: 2726
|
Firefighter Mitglied
11:31:23 31.08.2010 Titel: |
|
Zitieren |
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. |
_________________ Mein Blog
Clean-Code-Developer
Wie man richtig Fragen stellt
|
|
 |
David W
Mitglied
Benutzerprofil
Anmeldungsdatum: 09.08.2005
Beiträge: 4588
|
David W Mitglied
11:49:09 31.08.2010 Titel: |
|
Zitieren |
Wie wäre es mit dieser Idee?
| C# Code: | 1 2 3 4 5 6 7 8 9 10 11 12 | 1 2 3 4 5 6 7 8 9 10 11 12 | 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;
}
} | |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 11 12 | 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;
}
} | |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 11 12 | 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;
}
} | |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 | 1 2 3 4 5 6 7 8 9 10 | public class MyClass
{
private string m_name;
public string Name
{
get { return m_name; }
set { m_name = PropertySetter.Set(value); }
}
} | |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 | public class MyClass
{
private string m_name;
public string Name
{
get { return m_name; }
set { m_name = PropertySetter.Set(value); }
}
} | |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 | 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 |
_________________ My Libraries | aniwen
|
|
 |
Dravere
Moderator
Benutzerprofil
Anmeldungsdatum: 13.06.2005
Beiträge: 7252
|
Dravere Moderator
13:32:56 31.08.2010 Titel: |
|
Zitieren |
| 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 :P |
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.
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:
| C# Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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; }
}
| |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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; }
}
| |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 |
_________________ Danke für die Hilfe, Antwort oder Meinung!
C++: Std-Lib Referenz
C# .Net: MSDN kennt die Antwort
|
|
 |
David W
Mitglied
Benutzerprofil
Anmeldungsdatum: 09.08.2005
Beiträge: 4588
|
David W Mitglied
10:48:31 01.09.2010 Titel: |
|
Zitieren |
|
 |
Dravere
Moderator
Benutzerprofil
Anmeldungsdatum: 13.06.2005
Beiträge: 7252
|
Dravere Moderator
16:26:52 01.09.2010 Titel: |
|
Zitieren |
| 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:
| C# Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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.
| |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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.
| |
| C# Code: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
_________________ Danke für die Hilfe, Antwort oder Meinung!
C++: Std-Lib Referenz
C# .Net: MSDN kennt die Antwort
|
|
 |