2016-05-23 2 views
14

Интересно, если кто-то может объяснить, почему в этом кодеПочему динамический параметр в обобщенном методе генерирует исключение ссылочной ссылки при использовании объекта?

public class SomeClass 
{ 
    public T GenericMethod<T>(dynamic value) 
    { 
     return (T)value; 
    } 
} 

собой «возвращаемое значение;» оператор выдает нулевой ссылочный исключение при вызове с:

new SomeClass().GenericMethod<object>(new object()); // throws System.NullReferenceException 

Он работает, как и ожидалось, при вызове с:

new SomeClass().GenericMethod<string>("SomeString"); // returns SomeString 
new SomeClass().GenericMethod<object>("SomeString"); // returns SomeString 

Примечание: следующие компилирует и работает просто отлично

public class SomeOtherClass 
{ 
    public T GenericMethod<T>(object value) 
    { 
     return (T)value; 
    } 
} 

Штабеля:

System.NullReferenceException: Object reference not set to an instance of an object. 
    at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateLambda(EXPRCALL pExpr) 
    at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(EXPR pExpr) 
    at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.Rewrite(TypeManager typeManager, EXPR pExpr, IEnumerable`1 listOfParameters) 
    at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding) 
    at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding) 
    at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable`1 args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError) 
    at Microsoft.CSharp.RuntimeBinder.CSharpConvertBinder.FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion) 
    at System.Dynamic.DynamicMetaObject.BindConvert(ConvertBinder binder) 
    at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel) 
    at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args) 
    at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0) 
+0

Ницца найти! Надеюсь, у некоторых экспертов-компиляторов есть объяснение. –

+1

Я подозреваю, что это имеет какое-то отношение к динамическому приведению в 'T' (хотя фактический тип тот же). Если вы выполняете 'return value as T', это также работает. –

+0

Динамическое ключевое слово сообщает компилятору не применять дополнительные правила к вашему коду, поэтому я думаю, что это разрешено компилировать. Что касается фактического типа возвращаемого значения, то он выглядит так, как будто аргумент ввода значения содержит значение, и кажется, что вы можете использовать значение (например, значение «как T» работает) –

ответ

2

Оказывается it's a bug первый сообщалось в 2012 году, но до сих пор, по-видимому, не фиксирована (по состоянию на 24 мая 2016 года)

+0

Great Find - я отметил это как дубликат этого. –

+0

Действительно приятная находка! Предположим, что это единственный правильный ответ на этот вопрос – pvill

1

Update

Как marked duplicate указывает, что это известная ошибка в .NET время выполнения.


Проблема, вероятно, является плохой индикацией недействительного времени выполнения. Если вы берете динамическое связывание и сделать тип параметра object вы получите ошибку компилятора

Не удается неявно преобразовать тип «объект» на «Т». Явное преобразование существует (вы пропали без вести броска?)

С добавлением dynamic это отливка делаются во время выполнения, эта неявная ошибка преобразования проявляется по-разному во время выполнения с неопределенным NullReferenceException в RUN- временные привязки.

Я не специалист в области внутренней работы в DLR, но я подозреваю, что объект передается как значение dynamic не действительно чистый object во время выполнения. Я подозреваю, что это какая-то обертка вокруг object и поэтому не может быть неявно применена к объекту во время выполнения.

Явная ссылка отливать

return (T)(object)value; 

не будет генерировать эту ошибку.

+0

Это правильное значение 'return (T) (object);' удаляет ошибку, но в чем причина 'return (T) value'. Почему дополнительный прилив (объект) необходим – pvill

+0

@pvill, потому что тот же оператор-оператор также используется для выполнения преобразований в некоторых случаях (например, 'int i = 1; long l = (long) l;'). Это описано в разделе 6.2.7 спецификации C#. Добавление объекта cast в объект указывает, что операция является истинным ссылкой, а не неявным преобразованием. –

+0

Этот вид преобразования, указанный в этом конкретном разделе, здесь не требуется. 'new SomeClass(). GenericMethod (10);' отлично работает без модификации. И 'значение' относится к типу объекта, а' T' также является объектом. Не должно быть никакого преобразования ... – pvill

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