Компилятор C# выдает ошибку недопустимых аргументов.Почему?
Вопрос
У меня есть класс, который содержит два таких метода:
public String getFoo(Int32 a)
{
return getBar(a, "b", null);
}
public String getBar(Int32 a, String b, Int32 c)
{
//do something
return "";
}
Однако когда я компилирую свой класс, я получаю две ошибки:
- Лучшее совпадение перегруженного метода для getBar(int,string,int) имеет несколько недопустимых аргументов.
- Аргумент «3»:невозможно преобразовать из '
<null>
'к 'int'
Кажется, я понимаю, почему я получаю эту ошибку:Компилятор не знает во время компиляции, каков реальный тип объекта.Может ли кто-нибудь подтвердить, прав ли я относительно причины ошибки, или указать настоящую причину?
Что еще более важно, могу ли я спроектировать свой код таким образом?Если да, то что мне нужно сделать, чтобы исправить ошибки?Причина, по которой я разработал свой класс таким образом, заключается в том, что я не хочу дублировать код в getBar и в getFoo.Эти два метода делают по сути одно и то же, за исключением того, что один из них принимает третий параметр.
Спасибо.
Решение
В .NET существует четкое понятие между ссылочными типами и типами значений.
Ссылочный тип — это объект, который размещается в куче (это будет подкласс System.Object).Все, что находится в стеке, — это указатель на этот объект.По этой причине совершенно допустимо хранить нулевой указатель.
Тип значения — это объект, который выделяется в стеке и является подклассом System.ValueType.Поскольку тип значения находится в стеке, при передаче его значения функции вы передаете все содержимое объекта.
Типы значений не могут быть нулевыми.
Большинство примитивных типов C# являются типами значений.Строка — это особый тип примитива, который на самом деле является ссылочным типом.
В .NET 2.0 MS добавила возможность заключать универсальный тип внутри структуры, чтобы он мог имитировать тип, допускающий значение NULL.На самом деле происходит то, что логика внутри структуры Nullable<T> эмулирует для вас значение null.
Они выразили это, используя сокращение синтаксиса, добавив к типу вопросительный знак, например:
int? nullableInt = null;
float? nullableFloat = null;
и т. д...
Если вам не нравится int?синтаксис, вы всегда можете использовать Nullable<SomeType>
public String getBar(Int32 a, String b, Nullable<Int32> c)
В качестве примечания: я предпочитаю добавлять перегрузку при выполнении того, что делаете вы, просто чтобы сделать синтаксис лучше.
public String getBar(Int32 a, String b)
{
this.getBar(a,b,null);
}
public String getBar(Int32 a, String b, Nullable<Int32> c)
{
}
Другие советы
Int32
это тип значения, что означает null
не является допустимым аргументом для параметров типа Int32
.
Если вам действительно нужны нулевые целые числа, используйте int?
тип.
Две ошибки, которые вы видите, на самом деле являются одной и той же ошибкой.
Санни права.
Int32 является типом значения и не может содержать значение null.Если вам нужно передать «null» в качестве значения параметра, используйте Nullable вместо Int32 в качестве типа аргумента.
Вы можете найти дополнительную информацию на Типы, допускающие значение NULL (Руководство по программированию на C#) на MSDN.
Int32 — это псевдоним для int, который является типом значения или не допускающим значения NULL.Для версии с нулевым значением используйте System.Nullable или просто «int?».
Также не забудьте преобразовать обратно в необнуляемый int:
int? nullable = ...;
int non_nullable = nullable??0;
где число указывает, какое значение оно должно принять, если оно действительно равно нулю.
Int32 не может иметь значение null.Вместо этого сделайте его типом, допускающим значение NULL:
public String getBar(Int32 a, String b, Int32? c)
{
if (c.HasValue)
{
...do something with c.Value...
}
return "";
}
Итак пятьсемь человек предложили int?
как решение.Я предлагаю два других решения, которые мощь быть более уместным в зависимости от ситуации;
Создать перегрузку метода, который имеет только два аргумента, и опустите
null
при звонке:public String getFoo(Int32 a) { return getBar(a, "b", null); } public String getBar(Int32 a, String b) { //do something else, without the int }
Хотя вы, вероятно, не захотите этого делать, поскольку заявили, что хотите избежать дублирования кода.
Использовать
default
вместоnull
:return getBar(a, "b", default(int));
Кстати, это то же самое, что передать значение
0
.