operator c# nullreferenceexception nullable null-conditional-operator

operator - nameof c#



C#manera elegante de verificar si la propiedad de una propiedad es nula (21)

¿Puedes agregar un método a tu clase? Si no, ¿has pensado en usar métodos de extensión? Puede crear un método de extensión para su tipo de objeto llamado GetPropC() .

Ejemplo:

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; } }

Uso:

int val = ObjectA.GetPropC(0); // will return PropC value, or 0 (defaltValue)

Por cierto, esto supone que estás usando .NET 3 o superior.

En C #, diga que desea extraer un valor de PropertyC en este ejemplo y ObjectA, PropertyA y PropertyB pueden ser nulos.

ObjectA.PropertyA.PropertyB.PropertyC

¿Cómo puedo obtener PropertyC de forma segura con la menor cantidad de código?

Ahora mismo verificaría:

if(ObjectA != null && ObjectA.PropertyA !=null && ObjectA.PropertyA.PropertyB != null) { // safely pull off the value int value = objectA.PropertyA.PropertyB.PropertyC; }

Sería bueno hacer algo más así (pseudo-código).

int value = ObjectA.PropertyA.PropertyB ? ObjectA.PropertyA.PropertyB : defaultVal;

Posiblemente aún más colapsado con un operador de fusión nula.

EDITAR Originalmente dije que mi segundo ejemplo era como js, ​​pero lo cambié a código de pseudo porque se señaló correctamente que no funcionaría en js.


Acabo de tropezar con este post.

Hace algún tiempo hice una sugerencia sobre Visual Studio Connect sobre agregar un nuevo ??? operador.

http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4104392-add-as-an-recursive-null-reference-check-opera

Esto requeriría algo de trabajo del equipo de framework, pero no es necesario alterar el lenguaje, sino simplemente hacer algo de compilación mágica. La idea era que el compilador debería cambiar este código (sintaxis no permitida atm)

string product_name = Order.OrderDetails[0].Product.Name ??? "no product defined";

en este código

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()

Para un cheque nulo esto podría parecerse

bool isNull = (Order.OrderDetails[0].Product ??? null) == null;



Cuando necesito encadenar llamadas así, confío en un método de ayuda que creé, 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); }

En tu caso, lo usarías así:

int value = ObjectA .TryGet(p => p.PropertyA) .TryGet(p => p.PropertyB) .TryGet(p => p.PropertyC, defaultVal);


En C # 6 puede usar el Operador condicional nulo. Entonces la prueba original será:

int? value = objectA?.PropertyA?.PropertyB?.PropertyC;


Escribí un método que acepta un valor predeterminado, aquí se muestra cómo usarlo:

var teacher = new Teacher(); return teacher.GetProperty(t => t.Name); return teacher.GetProperty(t => t.Name, "Default name");

Aquí está el código:

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); } }


Escribiría su propio método en el tipo de PropertyA (o un método de extensión si no es su tipo) utilizando el patrón similar al tipo Nullable.

class PropertyAType { public PropertyBType PropertyB {get; set; } public PropertyBType GetPropertyBOrDefault() { return PropertyB != null ? PropertyB : defaultValue; } }


Este código es "la menor cantidad de código", pero no la mejor práctica:

try { return ObjectA.PropertyA.PropertyB.PropertyC; } catch(NullReferenceException) { return null; }


Este enfoque es bastante directo una vez que superas el 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); } }

Con un uso que podría verse así:

ObjectA objectA = null; Assert.AreEqual(0,objectA.GetPropertyOrDefault(prop=>prop.ObjectB.ObjectB.ObjectC.ID)); Assert.IsNull(objectA.GetPropertyOrDefault(prop => prop.ObjectB));


La forma en que lo haces es correcta.

Puede usar un truco como el que se describe here , usando expresiones Linq:

int value = ObjectA.NullSafeEval(x => x.PropertyA.PropertyB.PropertyC, 0);

Pero es mucho más lento que verificando manualmente cada propiedad ...


Método de extensión corta:

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); }

Utilizando

PropertyC value = ObjectA.IfNotNull(x => x.PropertyA).IfNotNull(x => x.PropertyB).IfNotNull(x => x.PropertyC);

Este sencillo método de extensión y mucho más se puede encontrar en http://devtalk.net/csharp/chained-null-checks-and-the-maybe-monad/

EDITAR:

Después de usarlo por un momento, creo que el nombre correcto para este método debería ser IfNotNull () en lugar del original With ().


Mira esta publicación de blog . Creo que es un método muy elegante para los controles nulos encadenados. Hay muchas implementaciones similares de esto, pero me gusta esta porque deja de evaluar tan pronto como se encuentra un valor nulo en la cadena.

Todo el código fuente está en github .


No es posible. ObjectA.PropertyA.PropertyB fallará si ObjectA es nulo debido a la desreferenciación nula, que es un error.

if (ObjectA! = null && ObjectA.PropertyA ... funciona debido a un cortocircuito, es decir, ObjectA.PropertyA nunca se comprobará si ObjectA es nulo.

La primera forma en que propones es la mejor y más clara con intención. Si algo puede intentar rediseñar sin tener que depender de tantos nulos.


Obviamente estás buscando la mónada Nullable :

string result = new A().PropertyB.PropertyC.Value;

se convierte

string result = from a in new A() from b in a.PropertyB from c in b.PropertyC select c.Value;

Esto devuelve null , si alguna de las propiedades que aceptan nulos es nula; de lo contrario, el valor de Value .

class A { public B PropertyB { get; set; } } class B { public C PropertyC { get; set; } } class C { public string Value { get; set; } }

Métodos de extensión 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); } }


Podrías hacer esto:

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; ... }

O incluso mejor podría ser esto:

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);



Suponiendo que tiene valores vacíos de tipos, un enfoque sería este:

var x = (((objectA ?? A.Empty).PropertyOfB ?? B.Empty).PropertyOfC ?? C.Empty).PropertyOfString;

Soy un gran fan de C #, pero una cosa muy buena en el nuevo Java (¿1.7?) Es el. operador:

var x = objectA.?PropertyOfB.?PropertyOfC.?PropertyOfString;


Vi algo en el nuevo C # 6.0, esto es mediante el uso de ''?'' en lugar de verificar

por ejemplo, en lugar de usar

if (Person != null && Person.Contact!=null && Person.Contact.Address!= null && Person.Contact.Address.City != null) { var city = person.contact.address.city; }

simplemente usa

var city = person?.contact?.address?.city;

Espero que haya ayudado a alguien.

ACTUALIZAR:

Podrías hacer esto así ahora

var city = (Person != null)? ((Person.Contact!=null)? ((Person.Contact.Address!= null)? ((Person.Contact.Address.City!=null)? Person.Contact.Address.City : null ) :null) :null) : null;


puedes usar la siguiente extensión y creo que es realmente buena:

/// <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); }

Y se usa así:

int value = Nulify.Get(objectA, x=>x.PropertyA, x=>x.PropertyB, x=>x.PropertyC);


Propagación nula planificada en C # vNext, con tecnología de Roslyn

No es una respuesta, sino más una actualización. Parece que UserVoice lo ha manejado, junto con otras cosas nuevas, desde Roslyn y aparentemente es una adición planeada:

https://roslyn.codeplex.com/discussions/540883


var result = nullableproperty ?? defaultvalue;

Los ?? operador significa que si el primer argumento es nulo, regrese el segundo en su lugar.