C # elegancki sposób na sprawdzenie czy właściwość danej nieruchomości jest null
W C# powiedz, że chcesz pobrać wartość z PropertyC w tym przykładzie, a ObjectA, PropertyA i PropertyB mogą być null.
ObjectA.PropertyA.PropertyB.PropertyC
Jak mogę bezpiecznie uzyskać PropertyC z jak najmniejszą ilością kodu?
Teraz sprawdziłbym:
if(ObjectA != null && ObjectA.PropertyA !=null && ObjectA.PropertyA.PropertyB != null)
{
// safely pull off the value
int value = objectA.PropertyA.PropertyB.PropertyC;
}
Byłoby miło zrobić coś takiego (pseudo-kod).
int value = ObjectA.PropertyA.PropertyB ? ObjectA.PropertyA.PropertyB : defaultVal;
Być może jeszcze bardziej upadł z null-koalescencji centrala.
EDIT początkowo mówiłem, że mój drugi przykład jest podobny do js, ale zmieniłem go na psuedo-code, ponieważ zostało poprawnie zaznaczone, że nie będzie działać w js.
19 answers
W C # 6 możesz użyć null Operator warunkowy. Więc oryginalny test będzie:
int? value = objectA?.PropertyA?.PropertyB?.PropertyC;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-01 08:43:59
Metoda Krótkiego Rozszerzenia:
public static TResult IfNotNull<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator)
where TResult : class where TInput : class
{
if (o == null) return null;
return evaluator(o);
}
Użycie
PropertyC value = ObjectA.IfNotNull(x => x.PropertyA).IfNotNull(x => x.PropertyB).IfNotNull(x => x.PropertyC);
Ta prosta metoda rozszerzenia i wiele więcej można znaleźć na http://devtalk.net/csharp/chained-null-checks-and-the-maybe-monad/
EDIT:
Po użyciu go przez chwilę myślę, że właściwa nazwa dla tej metody powinna być IfNotNull () zamiast oryginalna z().
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-19 17:10:52
Czy możesz dodać metodę do swojej klasy? Jeśli nie, Czy myślałeś o użyciu metod rozszerzeń? Możesz utworzyć metodę rozszerzenia dla swojego typu obiektu o nazwie GetPropC()
.
Przykład:
public static class MyExtensions
{
public static int GetPropC(this MyObjectType obj, int defaltValue)
{
if (obj != null && obj.PropertyA != null & obj.PropertyA.PropertyB != null)
return obj.PropertyA.PropertyB.PropertyC;
return defaltValue;
}
}
Użycie:
int val = ObjectA.GetPropC(0); // will return PropC value, or 0 (defaltValue)
Przy okazji, to zakłada, że używasz. NET 3 lub wyższej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-09 18:33:20
Sposób w jaki to robisz jest prawidłowy.
Możesz użyć sztuczki takiej jak ta opisana tutaj, używając wyrażeń Linq:
int value = ObjectA.NullSafeEval(x => x.PropertyA.PropertyB.PropertyC, 0);
Ale znacznie wolniejsze jest ręczne sprawdzanie każdej właściwości...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-12 13:06:32
Refaktor do przestrzegania Prawa Demeter
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-12 13:58:09
Update 2014: C # 6 ma nowy operator ?.
o nazwie "bezpieczna Nawigacja" lub "null"
parent?.child
Czytaj http://blogs.msdn.com/b/jerrynixon/archive/2014/02/26/at-last-c-is-getting-sometimes-called-the-safe-navigation-operator.aspx dla szczegółów
[[2]}to od dawna bardzo popularna Prośba https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c-?tracking_code=594c10a522f8e9bc987ee4a5e2c0b38dWarning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-06 18:31:42
Oczywiście szukasz Nullable Monad :
string result = new A().PropertyB.PropertyC.Value;
Staje się
string result = from a in new A()
from b in a.PropertyB
from c in b.PropertyC
select c.Value;
Zwraca null
, jeśli którakolwiek z właściwości nullable jest null; w przeciwnym razie wartość Value
.
class A { public B PropertyB { get; set; } }
class B { public C PropertyC { get; set; } }
class C { public string Value { get; set; } }
Metody rozszerzenia LINQ:
public static class NullableExtensions
{
public static TResult SelectMany<TOuter, TInner, TResult>(
this TOuter source,
Func<TOuter, TInner> innerSelector,
Func<TOuter, TInner, TResult> resultSelector)
where TOuter : class
where TInner : class
where TResult : class
{
if (source == null) return null;
TInner inner = innerSelector(source);
if (inner == null) return null;
return resultSelector(source, inner);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-12 14:40:53
Zakładając, że masz puste wartości typów, jedno podejście będzie takie:
var x = (((objectA ?? A.Empty).PropertyOfB ?? B.Empty).PropertyOfC ?? C.Empty).PropertyOfString;
Jestem wielkim fanem C# ale bardzo fajna rzecz w Nowej Javie (1.7?) jest .? operator:
var x = objectA.?PropertyOfB.?PropertyOfC.?PropertyOfString;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-12 14:01:01
Ten kod jest "najmniejszą ilością kodu", ale nie najlepszą praktyką:
try
{
return ObjectA.PropertyA.PropertyB.PropertyC;
}
catch(NullReferenceException)
{
return null;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-12 13:55:38
Kiedy muszę tak łączyć wywołania, polegam na stworzonej przeze mnie metodzie pomocniczej, TryGet ():
public static U TryGet<T, U>(this T obj, Func<T, U> func)
{
return obj.TryGet(func, default(U));
}
public static U TryGet<T, U>(this T obj, Func<T, U> func, U whenNull)
{
return obj == null ? whenNull : func(obj);
}
W Twoim przypadku, użyłbyś go tak:
int value = ObjectA
.TryGet(p => p.PropertyA)
.TryGet(p => p.PropertyB)
.TryGet(p => p.PropertyC, defaultVal);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-08 17:37:27
Widziałem coś w nowym C # 6.0, to przez użycie?"zamiast sprawdzać
Na przykład zamiast używać
if (Person != null && Person.Contact!=null && Person.Contact.Address!= null && Person.Contact.Address.City != null)
{
var city = person.contact.address.city;
}
Po prostu używasz
var city = person?.contact?.address?.city;
Mam nadzieję, że komuś to pomogło.
Aktualizacja:
Możesz zrobić tak teraz
var city = (Person != null)?
((Person.Contact!=null)?
((Person.Contact.Address!= null)?
((Person.Contact.Address.City!=null)?
Person.Contact.Address.City : null )
:null)
:null)
: null;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-15 13:03:13
Możesz to zrobić:
class ObjectAType
{
public int PropertyC
{
get
{
if (PropertyA == null)
return 0;
if (PropertyA.PropertyB == null)
return 0;
return PropertyA.PropertyB.PropertyC;
}
}
}
if (ObjectA != null)
{
int value = ObjectA.PropertyC;
...
}
A nawet lepiej może być to:
private static int GetPropertyC(ObjectAType objectA)
{
if (objectA == null)
return 0;
if (objectA.PropertyA == null)
return 0;
if (objectA.PropertyA.PropertyB == null)
return 0;
return objectA.PropertyA.PropertyB.PropertyC;
}
int value = GetPropertyC(ObjectA);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-12 14:03:56
Napisałbym własną metodę w typie Właściwości (lub metodę rozszerzenia, jeśli nie jest to Twój typ) używając podobnego wzorca do typu Nullable.
class PropertyAType
{
public PropertyBType PropertyB {get; set; }
public PropertyBType GetPropertyBOrDefault()
{
return PropertyB != null ? PropertyB : defaultValue;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-12 17:38:34
Możesz użyć następującego rozszerzenia i myślę, że jest to naprawdę dobre:
/// <summary>
/// Simplifies null checking
/// </summary>
public static TR Get<TF, TR>(TF t, Func<TF, TR> f)
where TF : class
{
return t != null ? f(t) : default(TR);
}
/// <summary>
/// Simplifies null checking
/// </summary>
public static TR Get<T1, T2, TR>(T1 p1, Func<T1, T2> p2, Func<T2, TR> p3)
where T1 : class
where T2 : class
{
return Get(Get(p1, p2), p3);
}
/// <summary>
/// Simplifies null checking
/// </summary>
public static TR Get<T1, T2, T3, TR>(T1 p1, Func<T1, T2> p2, Func<T2, T3> p3, Func<T3, TR> p4)
where T1 : class
where T2 : class
where T3 : class
{
return Get(Get(Get(p1, p2), p3), p4);
}
I używa się go tak:
int value = Nulify.Get(objectA, x=>x.PropertyA, x=>x.PropertyB, x=>x.PropertyC);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-10 07:49:36
Po prostu natknąłem się na ten post.
Jakiś czas temu zaproponowałem na Visual Studio Connect dodanie nowego operatora ???
.
Wymagałoby to trochę pracy ze strony zespołu framework, ale nie trzeba zmieniać języka, ale po prostu zrobić trochę magii kompilatora. Chodziło o to, aby kompilator zmienił ten kod (składnia nie dozwolone atm)
string product_name = Order.OrderDetails[0].Product.Name ??? "no product defined";
Do tego kodu
Func<string> _get_default = () => "no product defined";
string product_name = Order == null
? _get_default.Invoke()
: Order.OrderDetails[0] == null
? _get_default.Invoke()
: Order.OrderDetails[0].Product == null
? _get_default.Invoke()
: Order.OrderDetails[0].Product.Name ?? _get_default.Invoke()
Dla sprawdzenia null może to wyglądać
bool isNull = (Order.OrderDetails[0].Product ??? null) == null;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-10 06:56:05
Napisałem metodę, która akceptuje wartość domyślną, oto jak jej użyć:
var teacher = new Teacher();
return teacher.GetProperty(t => t.Name);
return teacher.GetProperty(t => t.Name, "Default name");
Oto kod:
public static class Helper
{
/// <summary>
/// Gets a property if the object is not null.
/// var teacher = new Teacher();
/// return teacher.GetProperty(t => t.Name);
/// return teacher.GetProperty(t => t.Name, "Default name");
/// </summary>
public static TSecond GetProperty<TFirst, TSecond>(this TFirst item1,
Func<TFirst, TSecond> getItem2, TSecond defaultValue = default(TSecond))
{
if (item1 == null)
{
return defaultValue;
}
return getItem2(item1);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-08 15:02:04
To niemożliwe.ObjectA.PropertyA.PropertyB
nie powiedzie się, jeśli ObjectA
jest null z powodu null dereferencing, co jest błędem.
if(ObjectA != null && ObjectA.PropertyA
... działa z powodu zwarcia, czyli ObjectA.PropertyA
nigdy nie będzie sprawdzane, Jeśli ObjectA
jest null
.
Pierwszy sposób, który proponujesz, jest najlepszy i najbardziej jasny z intencją. Jeśli coś, możesz spróbować przeprojektować bez konieczności polegania na tak wielu null.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-25 13:58:09
To podejście jest dość proste, gdy przejdziesz przez LAMBDA gobbly-gook:
public static TProperty GetPropertyOrDefault<TObject, TProperty>(this TObject model, Func<TObject, TProperty> valueFunc)
where TObject : class
{
try
{
return valueFunc.Invoke(model);
}
catch (NullReferenceException nex)
{
return default(TProperty);
}
}
Z użyciem, które może wyglądać następująco:
ObjectA objectA = null;
Assert.AreEqual(0,objectA.GetPropertyOrDefault(prop=>prop.ObjectB.ObjectB.ObjectC.ID));
Assert.IsNull(objectA.GetPropertyOrDefault(prop => prop.ObjectB));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-03 13:07:23
var result = nullableproperty ?? defaultvalue;
??
(operator null-coalescing) oznacza, że jeśli pierwszym argumentem jest null
, zwróć drugi.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-25 14:00:59