Создает ли общий метод С#, который допускает (нулевой) тип значения и ссылочный тип?

Я хочу создать простой метод, который принимает значения типа значения и ссылочного типа, т.е. int является значением, а строка является ссылкой.

Итак, я начинаю с:

public bool areBothNotNull<T>(T? p1, T? p2)
{
    return (p1.HasValue && p2.HasValue);
}

Итак, я хочу иметь возможность использовать его вот так:

var r1 = areBothNotNull<int>(3, 4); // will be true
var r2 = areBothNotNull<int>(3, null); // will be false
var r3 = areBothNotNull<string>("three", "four"); // will be true
var r4 = areBothNotNull<string>(null, "four"); // will be false

Но первая проблема, с которой я сталкиваюсь, -

Тип "T" должен быть невообразимым типом значения, чтобы использовать его как параметр "T" в родовом типе или методе "System.Nullable",

Чтобы продолжить, добавьте ограничение struct к моему методу

public bool areBothNotNull<T>(T? p1, T? p2) where T : struct

Но теперь метод не будет принимать строковые вызовы и даст мне эту ошибку:

Тип "string" должен быть невообразимым типом значения, чтобы использовать его как параметр "T" в родовом типе или методе.

Возможно ли это? Или почему мы не можем этого сделать?

Ответ 1

Ваша проблема в том, что вы хотите, чтобы общие ограничения типа противоречили друг другу:

  • Nullable<T> работает только с типами значений
  • Типы ссылок не являются типами значений

Таким образом, вам нужно будет иметь две перегрузки для работы вашего кода:

public static bool areBothNotNull<T>(T? p1, T? p2) where T : struct
{            
    return (p1.HasValue && p2.HasValue);
}

public static bool areBothNotNull<T>(T p1, T p2)
{
    return (p1 != null && p2 != null);
}

Тем не менее, следующая строка никогда не будет компилироваться:

var r3 = areBothNotNull<string>(3, 4);

Здесь существует конфликт, в котором аргумент generic type указывает, что параметры имеют тип string, но код пытается передать int.