Как будто вы пытаетесь получить доступ к объекту, который является null
. Рассмотрим ниже пример:
TypeA objA;
. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException
, что имеет смысл.
См. Также этот пример:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Устраняет ли компилятор во всех ограничениях типа типа при разрешении перегрузок?
blockquote>Нет, поскольку общие ограничения не являются частью сигнатуры функции. Вы можете проверить это, добавив перегрузку
Bar
, которая идентична, за исключением общих ограничений:interface IBar { } static void Bar<T>(IEnumerable<T> value) where T : IFoo { } static void Bar<T>(T source) where T : IBar { // fails to compile : Type ____ already defines a member called 'Bar' with the same parameter types }
Причина, по которой ваш код не компилируется, заключается в том, что компилятор выбирает «лучшее» соответствие на основе сигнатура метода , тогда пытается применить общие ограничения.
Одна из возможных причин, по которым это не , состоит в том, что этот вызов будет неоднозначным:
{предположим, что
List<T>
имеет методAdd<T>(IEnumerable<T> source
)}List<object> junk = new List<object>(); junk.Add(1); // OK junk.Add("xyzzy") // OK junk.Add(new [] {1, 2, 3, 4}); //ambiguous - do you intend to add the _array_ or the _contents_ of the array?
Очевидное исправление заключается в использовании другого имени для метода
Bar
, который принимает коллекцию (as выполняется в BCL сAdd
иAddRange
.
Это проблема ковариации . List<T>
не является ковариантным, поэтому между List<FooImpl>
и List<IFoo>
нет неявного преобразования.
С другой стороны, начиная с C # 4, IEnumerable<T>
теперь поддерживает ковариацию, поэтому это работает:
var value = Enumerable.Empty<FooImpl>();
Bar(value);
var value = new List<FooImpl>().AsEnumerable();
Bar(value);
var value = new List<FooImpl>();
Bar((IEnumerable<IFoo>)value);
FooImpl
? Я скоро обновлю вопрос.
– Dennis
25 September 2014 в 13:33
EDIT: Хорошо, причина, по которой Bar<T>(T source)
выбрана над Bar<T>(IEnumerable<T> source)
, когда передача списка происходит из-за раздела «7.5.3.2 Better function member
» ссылки на языке C #. В нем говорится, что при возникновении разрешения перегрузки типы аргументов сопоставляются типам параметров применимых членов функций (раздел 7.5.3.1), а лучший член функции выбирается с помощью следующего набора правил:
• для каждого аргумента неявное преобразование из EX в QX не лучше, чем неявное преобразование из EX в PX и
• по крайней мере для одного аргумента, преобразование из EX в PX лучше, чем преобразование из EX в QX.
blockquote>(PX - это типы параметров первого метода, QX второго)
Это правило применяется msgstr "после замены расширения и типа аргумента". Поскольку подстановка аргумента типа заменит Bar (источник T) на Bar> (источник IList), этот аргумент метода будет лучше, чем Bar (источник IEnumerable), который нуждается в преобразовании.
Я не мог " t найти онлайн-версию языковой ссылки, но вы можете прочитать ее здесь
РЕДАКТИРОВАТЬ: неправильно понял вопрос, работая над поиском правильного ответа на языке c # спекуляция В основном метод IIRC выбирается с учетом наиболее подходящего типа, и если вы точно не настроили свой параметр на
IEnumerable<>
, тоBar<T>(T source)
будет точно соответствовать типу параметра точно так же, как в этом примере:public interface ITest { } public class Test : ITest { } private static void Main(string[] args) { test(new Test() ); // outputs "anything" because Test is matched to any type T before ITest Console.ReadLine(); } public static void test<T>(T anything) { Console.WriteLine("anything"); } public static void test(ITest it) { Console.WriteLine("it"); }
Будет ссылаться на него, когда будет найден
Поскольку трансляция между массивом и перечислимым должна быть явной: это компилирует
var value = new FooImpl[0].AsEnumerable(); Bar(value);
, и так это:
var value = new FooImpl[0] as IEnumerable<IFoo>; Bar(value);
Из doc :
Начиная с .NET Framework 2.0 класс Array реализует System.Collections. Generic.IList, System.Collections.Generic.ICollection и System.Collections.Generic.IEnumerable общие интерфейсы. Реализации предоставляются массивам во время выполнения, и в результате общие интерфейсы не отображаются в синтаксисе объявления для класса Array.
blockquote>Таким образом, ваш компилятор не знает, что array соответствует сигнатуре для Bar, и вы должны явно использовать его
IEnumerable<T>
. Во-вторых, я понятия не имею, как мой вопрос коррелирует со ссылкой, которую вы предоставили.
– Dennis
25 September 2014 в 12:41
T
, используяBar<IFoo>(value);
– ken2k 25 September 2014 в 14:06