У меня есть класс с несколькими свойствами;
public class Employee
{
public string TYPE { get; set; }
public int? SOURCE_ID { get; set; }
public string FIRST_NAME { get; set; }
public string LAST_NAME { get; set; }
public List<Department> departmentList { get; set; }
public List<Address> addressList { get; set; }
}
иногда этот объект возвращает мне значение в любом свойстве, например
Employee emp = new Employee();
emp.FIRST_NAME= 'abc';
остальные значения равны нулю. Хорошо
Но как мне проверить, когда все ценности в свойствах объектов имеет значение null
вроде string.IsNullOrEmpty()
для объекта?
в настоящее время я проверяю вот так;
if (emp.FIRST_NAME == null && emp.LAST_NAME == null && emp.TYPE == null && emp.departmentList == null ...)
А как насчет создания в вашем классе функции, которая сделает это за вас? Так что вы вызываете его, когда вам это нужно.
Ваш текущий чек является надежным и читаемым. Вы можете разделить его на несколько строк (по одной проверке на строку), даже если это всего лишь огромное условие. Также несколько версий назад они добавили в C# 6 условные операторы NULL. Это может быть лучшим вариантом для однострочных проверок. docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
like string.IsNullOrEmpty() for object ?
Просто, чтобы прояснить, что может быть здесь недоразумение: объект, который является null
, не то же самое, что объект, все свойства которого являются null
. Если вы не будете различать их, вы столкнетесь с множеством недоразумений, когда будете говорить о своем коде.
@Flater есть много недоразумений по этому поводу, не могли бы вы предложить какие-нибудь хорошие чтения
Либо вы делаете это, записывая код для проверки каждого свойства вручную (лучший вариант), либо используете отражение (подробнее здесь)
Employee emp = new Employee();
var props = emp.GetType().GetProperties())
foreach(var prop in props)
{
if (prop.GetValue(foo, null) != null) return false;
}
return true;
пример из здесь
Обратите внимание, что int не может быть нулевым! и его значение по умолчанию будет 0. Таким образом, лучше проверить prop == default(int)
, чем == null
.
Другой вариант - реализовать INotifyPropertyChanged.
При изменении установите для логического поля isDirty
значение true, и вам нужно только проверить, истинно ли это значение, чтобы узнать, было ли установлено какое-либо свойство (даже если свойство было установлено с нулевым значением.
Предупреждение: в этом методе каждое свойство может иметь значение NULL, но проверяет только, был ли вызван установщик (изменение значения).
У них есть int?
, а не int
.
@trighati хорошо, но все же вы можете забыть сделать все свойства обнуляемыми.
@JoelHarkes, например?
@trighati int десятичные массивы, структуры с плавающей запятой и т. д.
Этот ответ получил несколько голосов в последний раз, поэтому я решил его немного улучшить, добавив простое кеширование, чтобы ArePropertiesNotNull
не извлекал свойства каждый раз, когда он вызывается, а только один раз для каждого типа.
public static class PropertyCache<T>
{
private static readonly Lazy<IReadOnlyCollection<PropertyInfo>> publicPropertiesLazy
= new Lazy<IReadOnlyCollection<PropertyInfo>>(() => typeof(T).GetProperties());
public static IReadOnlyCollection<PropertyInfo> PublicProperties => PropertyCache<T>.publicPropertiesLazy.Value;
}
public static class Extensions
{
public static bool ArePropertiesNotNull<T>(this T obj)
{
return PropertyCache<T>.PublicProperties.All(propertyInfo => propertyInfo.GetValue(obj) != null);
}
}
(Старый ответ ниже.)
Вы можете использовать отражение, предложенное Джоэл Харкес, например. Я собрал этот многоразовый, готовый к использованию метод расширения
public static bool ArePropertiesNotNull<T>(this T obj)
{
return typeof(T).GetProperties().All(propertyInfo => propertyInfo.GetValue(obj) != null);
}
который затем можно назвать так
var employee = new Employee();
bool areAllPropertiesNotNull = employee.ArePropertiesNotNull();
И теперь вы можете проверить флаг areAllPropertiesNotNull
, который указывает, не все ли свойства равны нулю. Возвращает true
, если все свойства не равны нулю, в противном случае - false
.
In my opinion, the slight performance overhead can be neglected since development time and repetition of code are reduced when using the ArePropertiesNotNull
, but YMMV.
Отражение также более перспективно, если вы измените класс и забудете изменить метод тестирования.
Итак ... что обычно медленнее в отражении, так это в той части, где вы пытаетесь найти все свойства (или что-то еще). Если это что-то, что нужно сделать много, кеширование свойств в массив значительно ускорит его.
@ThomasFlinkow Конечно.
All(propertyInfo => propertyInfo.GetValue(obj) != null)
вернет истину только в том случае, если свойства все равны нулю нет. Объект со всеми нулевыми свойствами будет отображать тот же результат (false), что и объект только с одним нулевым свойством (false), что не является точкой теста в соответствии с описанием OP. Я предполагаю, что вы имеете в виду Any(propertyInfo => propertyInfo.GetValue(obj) != null)
или ! All(propertyInfo => propertyInfo.GetValue(obj) == null)
(обратите внимание на инверсию на втором)
@ThomasFlinkow, пожалуйста, отредактируйте ответ с .Any
на .All
, чтобы я пометил его как принятый и предполагаю, что для .GetValue()
нужны два параметра, .GetValue(obj, null)
.
@trighati см. отредактированный ответ. Кроме того, хотя существует перегрузка PropertyInfo.GetValue(object, object)
, я решил использовать PropertyInfo.GetValue(object)
, чтобы мне не приходилось передавать null
. Конечно, вы можете использовать и то, и другое, это полностью зависит от вас и не будет иметь никакого значения. Спасибо, что отметили это как принятый.
У вашего объекта 6 свойств - одно из них даже не допускает значения NULL - что составляет 5. Лучше просто проверить каждое на значение NULL, чем какой-либо сложный сценарий, основанный на отражении. То, как вы это делаете, возможно, является способом верно.