Как создать экземпляр Nullable?
Предположим, у нас есть два класса:
public class ParentEntity
{
public ChildEntity Child { get; set; }
}
public class ChildEntity
{
public byte? NullableValue { get; set; }
public byte Value { get; set; }
}
задача состоит в том, чтобы выразить следующий код в выражениях linq:
parent.Child == null ? null : parent.Child.NullableValue
для этого я попытался использовать следующий код:
public static Expression GetCondition<TParent, TChild, TChildKey>(
Expression<Func<TParent, TChild>> pe,
Expression<Func<TChild, TChildKey>> ce)
{
var test = Expression.Equal(pe.Body, Expression.Constant(null));
var ifTrue = Expression.Constant(Activator.CreateInstance<TChildKey>());
var ifFalse = Expression.Property(pe.Body,
(ce.Body as MemberExpression).Member.Name);
return Expression.Condition(test, ifTrue, ifFalse);
}
запуск этого кода с помощью
Expression<Func<ParentEntity, ChildEntity>> pe = n => n.Child;
GetCondition(pe, n => n.Value); // ok
GetCondition(pe, n => n.NullableValue); // throws an ArgumentException
выдает ArgumentException
в последней строке (в инструкции return в GetCondition
), заявив, что типы аргументов не совпадают.
проанализировав этот код, я обнаружил, что Activator.CreateInstance<TChildKey>()
возвращает object
, но не TChildKey
, когда TChildKey
и System.Nullable<T>
, то есть ifTrue.Type
is object
, в то время как я ожидал, что это будет System.Nullable<byte>
.
этот вопрос обсуждается в SO: создание объекта nullable с помощью активатора.CreateInstance возвращает null указывая на отражение и Nullable
но ни один из них не предлагает ничего, чтобы решить эту проблему.
есть ли способ создать экземпляр точно System.Nullable<T>
типа, имеющие значение null
?
Или, может быть, есть какой-то другой способ выразить исходное условное выражение?
3 ответов
эта работа для вас!
public static Expression GetCondition<TParent, TChild, TChildKey>(
Expression<Func<TParent, TChild>> pe,
Expression<Func<TChild, TChildKey>> ce)
{
var test = Expression.Equal(pe.Body, Expression.Constant(null));
ConstantExpression ifTrue;
Type type = typeof(TChildKey);
// check if it is a nullable type
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof (Nullable<>))
{
ifTrue = Expression.Constant(default(TChildKey));
}
else
{
ifTrue = Expression.Constant( Activator.CreateInstance<TChildKey>());
}
var ifFalse = Expression.Property(pe.Body, (ce.Body as MemberExpression).Member.Name);
return Expression.Condition(test, ifFalse, ifFalse);
}
другой вариант-явно указать, какой тип константы создается Expression.Constant
используя перегрузку функции двух параметров.
var ifTrue = Expression.Constant(Activator.CreateInstance<TChildKey>(), typeof(TChildKey));
Nullable<>
требует очень тщательной обработки, особенно вокруг нулей. Быть явным полезно и часто необходимо, когда вы делаете что-либо вне нормы.