Как использовать универсальный интерфейс с двумя типами в возврате метода

#c# #generics #generic-constraints #generic-interface #generic-type-parameters

Вопрос:

Мне нужно создать интерфейс с типом 2 и использовать его в качестве возвращаемого значения метода.

 public interface StringLong<T1,T2>
where T1 : string
where T2 : long
{}

StringLong<T1,T2> method StringLong<T1,T2>()
 

Комментарии:

1. @OlivierRogier : вывод метода иногда бывает строковым, а иногда длинным или, возможно, другими типами в будущем.

2. @OlivierRogier — Хороший вопрос. Я надеюсь, что оперативная группа сможет ответить на этот вопрос в ближайшее время.

3. @OlivierRogier — Пожалуйста, избегайте редактирования ответов других людей и добавления информации. Решение о добавлении информации зависит от автора. Вместо этого лучше всего опубликовать запрос на дополнительную информацию в качестве комментария.

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

5. Аргумент «мне нужно» немного слаб. Не могли бы вы, пожалуйста, объяснить, почему вы так думаете?

Ответ №1:

Нет смысла определять интерфейс с двумя универсальными типами, которые вы ограничиваете только string и long .

Похоже, вам просто нужен кортеж:

 (string, long) MyMethod()
{
    return ("Hello", 42L);
}
 

Вы даже можете назвать возвращаемые значения:

 (string message, long meaningOfLife) MyMethod()
{
    return ("Hello", 42L);
}
 

Тогда вы сможете написать:

 var result = MyMethod();
Console.WriteLine(result.message);
Console.WriteLine(result.meaningOfLife);
 

Ответ №2:

Я думаю, что это функциональность, которую вы пытаетесь достичь (из комментариев). Так как возвращение может string быть либо long от одного, либо от общего предка object .

Как только у вас будет значение, вы можете использовать сопоставление с образцом, чтобы привести результат к соответствующему типу:

 static class Program
{
    static void Main(string[] args)
    {
        var obj = MethodReturnsStringOrLong(1722);
        switch (obj)
        {
            case string str:
                Console.WriteLine($"String is {str}");
                break;
            case long lng:
                Console.WriteLine($"Long is {lng}");
                break;
            default:
                throw new NotSupportedException();
        }
    }

    public static object MethodReturnsStringOrLong(int input)
    {
        if (input % 2 == 0)
        {
            return 1928374028203384L;
        }
        else
        {
            return "ASIDJMFHSOASKSJHD";
        }
    }
}
 

Альтернативой является создание собственного общего предка, например, класса Value ниже, который может содержать либо a long и/или a string .

 public class Value
{
    public Value(long longValue)
    {
        LongValue = longValue;            
    }
    public Value(string stringValue)
    {
        StringValue = stringValue;
    }

    public long? LongValue { get; }
    public string StringValue { get; }
}


static class Program
{
    static void Main(string[] args)
    {
        var obj = MethodReturnsStringOrLong(1722);
        if (obj.LongValue.HasValue)
        {
            Console.WriteLine($"Long is {obj.LongValue.Value}");
        }
        if (!string.IsNullOrEmpty(obj.StringValue))
        {
            Console.WriteLine($"String is {obj.StringValue}");
        }
    }

    public static Value MethodReturnsStringOrLong(int input)
    {
        if (input % 2 == 0)
        {
            return new Value(1928374028203384L);
        }
        else
        {
            return new Value("ASIDJMFHSOASKSJHD");
        }
    }

}