Хотя можно получить код рабочего, так что правильные лямбды построены и скомпилированы, использования неоднократно скомпилированные лямбд для достижения нулевой проверки является дорогостоящим излишеством.
Как правило, использование lambdas так случайно (скомпилирование лямбда для каждого свойства в цепочке и одном объекте) сопровождается заметным поражением производительности. Я запустил несколько тестов, и на моем компьютере, выполняющем этот метод 1000 раз для данного объекта, было задано время ~ 300-700 мс (в зависимости от количества свойств в цепочке). Dunno, сколько организаций вы имеете дело, но это не хороший знак, и лучшие замены доступны. Пожалуйста, прочтите далее ...
Вопрос в том, для чего вы это используете? Этот ваш метод напоминает мне null-conditional operators довольно много. В общем, если вы:
- просто хотите проверить, если какое-либо имущество в цепи собственности является нулевой
- использования C# 6
- имеет все параметры цепь лямбда (как
x => x.Property1.List1
) известно во время выполнения
Тогда вы можете ломом весь этот метод IsAnyMemberNull вообще в пользу чего-то вроде:
object1.Property1.List1 == null
Гораздо более кратким и не требуются дополнительные методы. Я побежал его 1 миллион раз, и он все еще находился в пределах ~ 23 мс. Это означает, что это на десятки тысяч быстрее, чем создание всех этих лямбдов.
Если вы не можете использовать нуль-сливающихся операторы по каким-либо причинам (особенно, когда выражение строится динамически), вы могли бы вместо этого решили использовать поле/отражение свойств.
Я взял на себя смелость удалить всю эту оболочку общего класса в пользу универсального метода.Из вашего примера использования, казалось, единственная цель универсального класса заключалась в доступе к определенному методу с параметрами generic типа класса. Это означает, что для каждого варианта метода необходимо будет создать и сохранить каждый новый класс без видимых причин, если я не ошибаюсь, для остальной части приложения. Общие методы в конкретных классах обычно предпочтительнее конкретных методов в родовых классах, в таких случаях.
Кроме того, я удалил IList, потому что я не вижу причин, по которым требуется, чтобы последний параметр был типа IList, служит для функции; это ограничивает его применимость без видимого усиления.
В целом, результат состоит в следующем:
public bool IsAnyMemberNull<TEntity, TMember>(Expression<Func<TEntity, TMember>> paramChain, TEntity entityDb)
{
var expressionsToCheck = new List<MemberExpression>();
var expression = paramChain.Body as MemberExpression;
while (expression != null)
{
expressionsToCheck.Add(expression);
expression = expression.Expression as MemberExpression;
}
object value = entityDb;
for (var i = expressionsToCheck.Count - 1; i >= 0; i--)
{
var member = expressionsToCheck[i].Member;
if (member is PropertyInfo) value = (member as PropertyInfo).GetValue(value);
else if (member is FieldInfo) value = (member as FieldInfo).GetValue(value);
else throw new Exception(); // member generally should be a property or field, shouldn't it?
if (value == null)
return true;
}
return false;
}
После запуска этого ~ 1000 раз, потребовалось около 4-6ms; В 50-100 раз лучше, чем лямбда, хотя до сих пор господствует нулевое распространение.
Вызывается следующим образом (предполагается, что он все еще находится в TestClass, что это не нужно):
new TestClass().IsAnyMemberNull<Class1,Class2>(x => x.Property1.List1, object1);
(Class1 и Class2 не могут быть необходимыми, благодаря типу умозаключения)
Надеюсь, что это поможет. Это не совсем то, о чем вы просили, но я боюсь, что со всем этим лямбда-нерестом вы столкнетесь с серьезными проблемами производительности; особенно если этот код должен использоваться много раз за запрос.