2015-10-26 4 views
2

Я пытаюсь использовать выражение для создания этого:Expression.Condition: типы аргументов не соответствуют

bool.Parse("true") ? default(int?) : 1 

BTW, я использую bool.Parse("true") просто держать VS от жалуясь недостижимыми путями коды, так просто предположим, что он использует константу true. Когда я пишу мое выражение, как это ...

Expression.Condition(Expression.Constant(true), Expression.Default(typeof(int?)), 
    Expression.Constant(1)) 

... Я получаю ошибку Argument types do not match. Я почти уверен, что я в курсе того, что происходит, поэтому я изменил свое выражение, чтобы сделать это:

Expression.Condition(Expression.Constant(true), Expression.Default(typeof(int?)), 
    Expression.New(typeof(int?).GetConstructor(new[] { typeof(int) }), Expression.Constant(1))); 

Это работает, но я не могу сказать, что я люблю писать выражение, которое является эквивалентом этого:

bool.Parse("true") ? default(int?) : new int?(1) 

Есть ли способ заставить это тернарное выражение работать без создания нового экземпляра int?? Возможно, это нормально, потому что C# неявно создает новый экземпляр в моем конкретном примере?

Редактировать

Я должен отметить, что я только использую Expression.Constant() эмулировать возвращаемое значение из MethodCallExpression для того, чтобы упростить мой пример кода. Поэтому в этом случае все, что предполагает использование постоянных значений в качестве решения, не будет работать.

+0

Я не понимаю, в чем проблема с 'new int? (1)'. Что именно вам не нравится в этом? – svick

+0

@svick Я не хочу создавать новый экземпляр чего-то, когда могу просто повторно использовать существующий экземпляр. Мне нравится ответ dasblinkenlight, который предлагает лить в 'int?'. – oscilatingcretin

+0

Какой пример? 'int?' не является ссылочным типом, а C# 'new' не является C++' new'. 'new int? (1)' делает то же самое, что и '(int?) 1'. – svick

ответ

4

Вы можете создать слепок вместо создания экземпляра с new, т.е.

bool.Parse("true") ? default(int?) : (int?)(1) 

так:

Expression.Condition(
    Expression.Constant(true) 
, Expression.Default(typeof(int?)) 
, Expression.Convert(Expression.Constant(1), typeof(int?)) 
) 

Demo.

+0

Я не думал об этом, но я надеялся избежать актерского мастерства над тем, над чем я работаю. Однако, возможно, это не проблема, так как, вероятно, неявный «int-to-int?» Приступает, когда я назначаю значение тернарного выражения моей переменной «int?». Можете ли вы подтвердить, так ли это? – oscilatingcretin

+0

@oscilatingcretin К сожалению, вам нужен актерский состав или явный тип. В отличие от компилятора C#, который является умным для вставки бросков неявно для вас, выражения LINQ требуют, чтобы вы были конкретны в отношении типов выражений с обеих сторон, даже если вы явно указываете общий тип выражения (см. Arg # 4 в демо). Когда вы назначаете выражение, возвращающее 'int' в' int? ', Компилятор вставляет для вас неявный бросок; LINQ требует от вас выражения 'Convert'. – dasblinkenlight

+0

Поскольку '(int?) (1)' является компиляцией времени, более близкой аналогией было бы ввести константу, а не использовать 'Convert'. –

1

когда вы пишете bool.Parse("true") ? default(int?) : 1 это на самом деле компилируется к чему-то больше похожее на:

bool.Parse("true") ? default(int?) : new int?(1) 

Так почему бы не просто использовать константу int? со значением 1, например, так:

Expression.Condition(Expression.Constant(true), 
    Expression.Default(typeof(int?)), 
    Expression.Constant(1, typeof(int?))) 

Этой перегрузка Expression.Constant должна быть использована в качестве сдачи int? как object либо окна лежащего в основе int или пропуска null, вы должны явно сказать, что это константа int?.

1

Введите константа с:

Expression.Condition(Expression.Constant(true), 
    Expression.Default(typeof(int?)), 
    Expression.Constant(1, typeof(int?))) 

Или введите условное выражение с:

Expression.Condition(Expression.Constant(true), 
    Expression.Default(typeof(int?)), 
    Expression.Constant(1), 
    typeof(int?)) 

Первые изменения, как постоянные работы (в обоих случаях значение хранится в виде коробочной int , так же, как и для константы int, и при необходимости распаковывается int?.

Вторым является условие, в котором хранится тип, на который должны быть направлены оба операнда.

Обратите внимание, что не может быть никакого фактического литья, особенно с первыми двумя, например. если вы скомпилируете, вы, скорее всего, скомпилируете форму, которая действует непосредственно на int?, поэтому, если объект выражения требует, чтобы актер действовал, скомпилированный код, который он производит, не работает.

Обратите внимание, что некоторые провайдеры не могут обрабатывать типизированные условия, делая последнюю возможность недоступной. Например. EnumerableQuery не могут с ними справиться (см. https://github.com/dotnet/corefx/issues/3607).