Связать два общих типа

#c# #generics #traits

#c# #общие #Трейты

Вопрос:

У меня есть две параллельные иерархии классов, где первая иерархия предназначена для API, а вторая используется на уровне модели. Один и тот же тип имеет одно представление (класс) в каждой иерархии, и я хочу «связать» (подробнее позже) эти два класса, чтобы использовать общие.

       API
     /   
 ApiA     ApiB

     Model
     /   
ModelA    ModelB
  

Например, как только эта функция

 public string DoSomething<APIType> (APIType value) {
  

получает APIType в качестве аргумента (например, ApiB), я хочу вызвать связанный универсальный метод, который принимает ModelType в качестве аргумента типа (в данном случае ModelB).

Я попробовал что-то похожее на это: общедоступная строка doSomething (значение ApiType), где ModelType: модель, где ApiType: API

Но затем я обнаруживаю, что C # не может выполнять частичный вывод, так что это:

 class ApiB : Api<ModelB> {}

ApiB obj;
DoSomething(obj) 
  

не может работать (требуются оба аргумента типа)

Я попытался реализовать что-то похожее на черты C , но это не сработало. Можно было бы использовать только тип, но я делаю это для того, чтобы получить дополнительную проверку компилятора.

Я думаю, это не большая проблема, однако я хотел бы знать, знает ли кто-нибудь решение.

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

1. Я чувствую, что если ваш ApiA имеет смысл только с ModelA, тогда он должен подкласс API<ModelA> с конкретной моделью, и не должен быть универсальным

Ответ №1:

Это очень сложный вопрос. Проверьте этот код, я заменил associated generic method call на универсальный конструктор List . Комментарий, если есть разница между тем, что вы спросили, и тем, что я понял из вопроса.

 class Program
{
    public class Model { }

    public class ModelB : Model { }

    public class Api<T> where T : Model
    {
        public List<T> CallGenericMethod()
        {
            return new List<T>();
        }
    }

    public class ApiB: Api<ModelB> { }

    public static string DoSomething<T>(Api<T> a) where T : Model
    {
        var b = a.CallGenericMethod();
        return b.GetType().ToString();
    }

    static void Main(string[] args)
    {
        ApiB a = new ApiB();
        Console.WriteLine(DoSomething(a));
    }
}
  

Редактирование двух типов универсальной версии

 public class Api<TApi, TModel> where TApi: Api<TApi, TModel> where TModel : Model
{
    public List<TModel> CallGenericMethod()
    {
        return new List<TModel>();
    }
}

public class ApiB: Api<ApiB, ModelB> { }

public static string DoSomething<TApi, TModel>(Api<TApi, TModel> a) where TApi : Api<TApi, TModel> where TModel: Model
{
    return new Dictionary<TApi, TModel>().GetType().ToString();
}
  

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

1. Он выполняет свою работу, однако мне придется редактировать Api каждый раз, когда я хочу добавить новый метод, который использует этот тип модели generic, поэтому это не лучшее решение (однако кажется, что оно единственное жизнеспособное в C #)

2. @Clynamen Если DoSomething вы вызовете new List<T>() его List<ModelB> , он также будет создан.

3. Раньше я не понимал, что вы не использовали generic в doSomething для APIType , как в вопросе. Я мог бы попытаться заменить это и использовать простое наследование, как вы это сделали

4. @Clynamen Можно использовать оба типа, но немного уродливее.

5. к сожалению, да (это я хотел сказать ранее о частичном выводе). Кстати, я хотел бы избежать этого, поскольку это сделало бы код действительно запутанным (это будет использоваться несколько раз)