CS0411 Аргументы типа, полученные из использования [duplicate]

Если мы рассмотрим общие сценарии, в которых может быть выбрано это исключение, доступ к свойствам с объектом вверху.

Пример:

string postalcode=Customer.Address.PostalCode; 
//if customer or address is null , this will through exeption

здесь, если адрес равен нулю, то вы получите NullReferenceException.

Итак, в качестве практики мы всегда должны использовать проверку нуля, прежде чем обращаться к свойствам в таких объектах (особенно в общих)

string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
48
задан John Saunders 29 August 2010 в 04:44
поделиться

7 ответов

Общий принцип здесь состоит в том, что информация типа течет только «в одну сторону», от внутри до вне выражения. Пример, который вы даете, чрезвычайно прост. Предположим, мы хотели иметь поток информации о типе «в обоих направлениях» при выполнении вывода типа в методе R G<A, R>(A a) и рассмотреть некоторые из сумасшедших сценариев, которые создают:

N(G(5))

Предположим, что существует десять различных перегрузок N, каждый из которых имеет другой тип аргумента. Должны ли мы сделать десять разных выводов для R? Если бы мы это сделали, мы бы как-то выбрали «лучший»?

double x = b ? G(5) : 123;

. Каким должен быть тип возврата G? Int, потому что другая половина условного выражения является int? Или двойной, потому что в конечном итоге эта вещь будет назначена на двойной? Теперь, возможно, вы начинаете видеть, как это происходит; если вы скажете, что вы рассуждаете извне внутрь, , как далеко вы идете ? Может быть много шагов на этом пути. Посмотрите, что произойдет, когда мы начнем их комбинировать:

N(b ? G(5) : 123)

Теперь что мы будем делать? У нас есть десять перегрузок из N на выбор. Считаем ли мы, что R является int? Это может быть int или любой тип, который int неявно конвертируется в. Но из тех типов, какие из них неявно конвертируются в тип аргумента N? Разве мы пишем себе небольшую прологическую программу и просим движок пролога решить, какие все возможные типы возврата могут быть R, чтобы удовлетворить каждую из возможных перегрузок на N, а затем как-то выбрать лучший?

(Я не шучу, есть языки, которые по существу делают , пишут небольшую прологическую программу, а затем используют логический движок, чтобы определить, что такое все. F # для например, делает более сложный вывод типа, чем C #. Система типов Haskell на самом деле является Turing Complete, вы можете кодировать произвольно сложные проблемы в системе типов и попросить компилятор их решить. Как мы увидим позже, это же верно для разрешение перегрузки в C # - вы не можете кодировать проблему с остановкой в ​​системе типа C #, как вы можете в Haskell, но вы можете кодировать проблемы NP-HARD в проблемы с разрешением перегрузки.)

Это все еще очень простое выражение. Предположим, у вас было что-то вроде

N(N(b ? G(5) * G("hello") : 123));

. Теперь мы должны решить эту проблему несколько раз для G и, возможно, и для N, и мы должны решить их в комбинации . У нас есть пять проблем разрешения перегрузки для решения, и всех из них, если быть справедливым, следует рассматривать как их аргументы, так и их тип контекста. Если для N существует десять возможностей, то для N (N (...)) существует потенциально сотни возможностей и тысяча для N (N (N (...))), и очень быстро вы должны решить проблему проблемы, которые легко имели миллиарды возможных комбинаций и сделали компилятор очень медленным.

Вот почему у нас есть правило, которое вводит информацию только в одном направлении. Он предотвращает такие виды проблем с курицей и яйцами, где вы пытаетесь определить внешний тип из внутреннего типа и определить внутренний тип из внешнего типа и вызвать комбинаторный взрыв возможностей.

Примечание эта информация типа течет в обоих направлениях для лямбда! Если вы скажете N(x=>x.Length), то достаточно уверен, мы рассмотрим все возможные перегрузки N, которые имеют функции или типы выражений в своих аргументах и ​​опробовать все возможные типы для x. И, конечно, есть ситуации, в которых вы можете легко заставить компилятор опробовать миллиарды возможных комбинаций , чтобы найти уникальную комбинацию, которая работает. Правила вывода типа, которые позволяют сделать это для общих методов, чрезвычайно сложны и заставляют даже нервировать Джона Скита. Эта функция делает разрешение перегрузки NP-HARD .

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

85
ответ дан Eric Lippert 31 August 2018 в 12:58
поделиться

Вы должны сделать:

string dest = Gimme<int, string>(5);

Вам нужно указать, какие ваши типы находятся в вызове общего метода. Как он мог знать, что вам нужна строка в выходе?

System.String - плохой пример, потому что это запечатанный класс, но сказать, что это не так. Как компилятор мог знать, что вы не хотите использовать один из своих подклассов, если вы не указали тип в вызове?

Возьмем этот пример:

System.Windows.Forms.Control dest = Gimme(5);

Как компилятор узнает, какой контроль на самом деле сделать? Вам нужно будет указать его так:

System.Windows.Forms.Control dest = Gimme<int, System.Windows.Forms.Button>(5);
7
ответ дан Dave Markle 31 August 2018 в 12:58
поделиться

Это было дизайнерское решение, которое я предполагаю. Я также считаю это полезным при программировании на Java.

В отличие от Java, C #, похоже, развивается по направлению к функциональному языку программирования, и вы можете получить вывод типа наоборот, так что вы можете иметь:

var dest = Gimme<int, string>(5);

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

1
ответ дан Grzenio 31 August 2018 в 12:58
поделиться

Вызов Gimme(5) игнорирование возвращаемого значения является юридическим утверждением, как компилятор узнает, какой тип будет возвращен?

5
ответ дан Jerod Houghtelling 31 August 2018 в 12:58
поделиться
public class ReturnString : IReq<string>
{
}

public class ReturnInt : IReq<int>
{
}

public interface IReq<T>
{
}

public class Handler
{
    public T MakeRequest<T>(IReq<T> requestObject)
    {
        return default(T);
    }
}

var handler = new Handler();
string stringResponse = handler.MakeRequest(new ReturnString());
int intResponse = handler.MakeRequest(new ReturnInt());
0
ответ дан Kin Liang Choong 31 August 2018 в 12:58
поделиться

Я использую этот метод, когда мне нужно сделать что-то подобное:

static void Gimme<T>(out T myVariable)
{
    myVariable = default(T);
}

и использовать его следующим образом:

Gimme(out int myVariable);
Print(myVariable); //myVariable is already declared and usable.

Обратите внимание, что встроенное объявление внешних переменных доступный с C # 7.0

0
ответ дан nobody 31 August 2018 в 12:58
поделиться

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

0
ответ дан supercat 31 August 2018 в 12:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: