Компилятор C # выдает ошибку неверных аргументов. Зачем? - PullRequest
1 голос
/ 07 ноября 2008

У меня есть класс, который содержит два метода, подобные этим:

public String getFoo(Int32 a)
{
  return getBar(a, "b", null);
}

public String getBar(Int32 a, String b, Int32 c)
{
  //do something
  return "";
}

Однако, когда я собираю свой класс, я получаю две ошибки:

  1. Наилучшее перегруженное совпадение методов для getBar (int, string, int) имеет недопустимые аргументы
  2. Аргумент '3': невозможно преобразовать из '<null>' в 'int'

Мне кажется, я понимаю, почему я получаю эту ошибку: компилятор не знает во время компиляции, каков реальный тип объекта. Может ли кто-нибудь подтвердить, правильно ли я объясняю причину ошибки, или указать истинную причину?

Что более важно, могу ли я разработать свой код таким образом? Если так, что мне нужно сделать, чтобы исправить ошибки? Моя причина для разработки моего класса таким образом, потому что я не хочу дублировать код в getBar, в getFoo. Два метода делают одно и то же, за исключением одного, принимающего третий параметр.

Спасибо.

Ответы [ 7 ]

8 голосов
/ 07 ноября 2008

В .NET существует четкое понятие между ссылочными типами и типами значений.

Тип ссылки - это объект, который размещается в куче (это будет подкласс System.Object). Все, что находится в стеке, это указатель на этот объект. Поэтому вполне допустимо хранить нулевой указатель.

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

Типы значений не могут быть нулевыми.

Большинство примитивных типов C # являются типами значений. String - это особый тип примитива, который на самом деле является ссылочным типом.

В .NET 2.0 MS добавила возможность заключать универсальный тип в структуру, чтобы она могла имитировать обнуляемый тип. Что действительно происходит, так это то, что логика внутри структуры Nullable эмулирует для вас нуль.

Они выразили это, используя синтаксическое сокращение, добавив знак вопроса к типу, например:

int? nullableInt = null;
float? nullableFloat = null;

и т.д ...

Если вам не нравится int? синтаксис, вы всегда можете использовать Nullable

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)
{
}
2 голосов
/ 07 ноября 2008

Попробуйте сделать третий аргумент для getBar обнуляемым int.

Итак, подпись будет выглядеть так:

public String getBar(Int32 a, String b, Int32? c)

Подробнее об обнуляемых типах можно узнать в .NET здесь и здесь .

1 голос
/ 07 ноября 2008

Солнечно правильно.
Int32 является типом значения и не может содержать значение 'null'. Если вам нужно передать 'null' в качестве значения параметра, используйте Nullable вместо Int32 в качестве типа аргумента.

Дополнительную информацию можно найти по адресу Обнуляемые типы (Руководство по программированию в C #) в MSDN.

1 голос
/ 07 ноября 2008

Int32 - это псевдоним для int, который является значением / ненулевым типом. Для допустимой версии используйте System.Nullable или просто 'int?'.

Также не забудьте преобразовать обратно в необнуляемое целое число:

int? nullable = ...;
int non_nullable = nullable??0; 

где число указывает, какое значение оно должно принимать, если оно действительно равно нулю.

1 голос
/ 07 ноября 2008

Int32 является типом значения, что означает, что null не является допустимым аргументом для параметров типа Int32.

Если вам действительно нужны пустые значения, используйте тип int?.

Две ошибки, которые вы видите, на самом деле являются одной и той же ошибкой.

0 голосов
/ 07 ноября 2008

ОК, поэтому пять семь человек предложили 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.

0 голосов
/ 07 ноября 2008

Int32 не может быть нулевым. Вместо этого сделайте его обнуляемым:

public String getBar(Int32 a, String b, Int32? c)
{
    if (c.HasValue)
    {
        ...do something with c.Value...
    }
    return "";
}
...