2016-11-15 5 views
2

Я пишу метод со следующей подписью:Возможная ошибка компилятора при генерации шаблонный метод

public class Map<TSource,TDestination> 
{ 
    public void Map<TSourceProperty, TDestinationProperty>(
      Expression<Func<TSource, TSourceProperty>> sourcePropertySelector, 
      Expression<Func<TDestination, TDestinationProperty>> destinationPropertySelector, 
      Expression<Func<TSourceProperty, TDestinationProperty>> converter){} 

} 

метод вызывается так:

example1- Map(a => a.StringProperty, b => b.IntProperty, c => Int32.Parse(c)) 
example2- Map(a => a.NullabelInt32, b => b.Int32, c => c == null ? 0 : c) 

При вызове этого метода это случается, что TDestinationProperty не всегда имеет правильный тип, то есть тип выбранного объекта.

В приведенном выше примере 1 TDestinationProperty является правильным видом типа Int32; но в примере 2 TDestinationProperty всегда заканчивается тем же, что и TSourceProperty, то есть в примере2 конкретного случая, Nullable<int>.

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

Чтобы быть честным, у меня все еще есть рабочий обход для этого, но дело в том, чтобы понять, есть ли у меня какая-то ошибка компиляции или что-то в этом роде.

Есть идеи? Можете ли вы воспроизвести это?

+0

Будет ли это работать: '... c => c == null? 0: c.Value) '? –

+0

Вы можете сделать 'c => c ??0'. – juharr

+0

Замечание: пожалуйста, перечитайте руководство [MCVE] ... На самом деле вам не нужен такой сложный тип, чтобы показать поведение - одного параметра будет достаточно «Map (Func > converter) ... и 'c => c == null? 0: c' можно упростить до 'c => c' ... –

ответ

2

Проблема является оператором ?:, он будет возвращать тип, который совместим с обеих 0 и c которая Nullable<int>, потому что c является Nullable<int>. И поскольку, если имеет номер TDestinationProperty, то b.Int32 все равно будет законным типом возврата из-за автоматического продвижения типов, в котором он использует третий параметр для определения типа.

Если вы измените 2-й линии в

Map(a => a.NullabelInt32, b => b.Int32, c => c == null ? 0 : c.Value) 

он должен работать нормально.

+0

Небольшое удовлетворение, которое мне нравится делиться: я очень рад сказать, что что-то сверкнуло в моей голове, когда я заснул сегодня вечером, и, наконец, я понял это себя. Очень вздыматься, чтобы проснуться и посмотреть на мой вопрос, и мои мысли подтвердились. Большое спасибо за краткое объяснение. – sam

3

Итак, давайте посмотрим, что компилятор может вывести из выражения Expression<Func<TSourceProperty, TDestinationProperty>> converter при передаче лямбда c => c == null ? 0 : c. Мы знаем, что c является Nullable<int> из разрешения первого параметра, поэтому TSourceProperty - Nullable<int>. У вас, похоже, нет никаких проблем с этим. Итак, какова ценность этого выражения? Выражение вызывает условный оператор; первый операнд имеет тип int, а вторая операция имеет тип Nullable<int>, так как это c есть. Итак, каков должен быть тип всего условного оператора? Ну, так как int неявно конвертируются в Nullable<int> и Nullable<int> является не неявно конвертируется в int, тип всего условного оператора на это Nullable<int>, что делает, что тип возвращаемого значения лямбды, что делает его типа TDestinationProperty ,

Если вы хотите TDestinationProperty быть int, то вам нужно конвертировать c в int в этом лямбда. Вы могли бы написать: c => c == null ? 0 : c.Value, но все это можно просто сократить до c => c.GetValueOrDefault().

+0

Это также правильный ответ, я просто предпочитаю @ScottChamberlain, потому что он более краток. Спасибо! – sam

Смежные вопросы