Хранить реализацию интерфейса generi c в списке - PullRequest
1 голос
/ 03 марта 2020

Я пытаюсь создать службу, которая управляет различными поставщиками учетных записей и учетными записями в нашем приложении (настольное приложение WPF).

Моя идея заключалась в том, чтобы иметь поставщиков учетных записей, которые были бы внешними веб-службами, такими как Jira. , Gitlab и др. c. У каждого провайдера есть список с учетными записями.

В зависимости от провайдера у него могут быть разные способы авторизации нашего программного обеспечения для использования учетной записи пользователя. Наша первая реализация использует токены OAuth для авторизации и API отдыха для взаимодействия с веб-службой.

Очевидно, нам нужны некоторые ограничения, например, OAuthProvider будет принимать OAuthAccounts только в своем списке учетных записей.

Идеальным вариантом было бы, если бы мы могли хранить всех провайдеров независимо от типа их счетов в едином списке вида List<IAccountProvider<IAccount>> someList. Однако я не мог заставить это скомпилировать. Ошибка:

Error CS1503 Argument 1: cannot convert from 'TestProject.Program.JiraProvider' to 'TestProject.Program.IAccountProvider<TestProject.Program.IAccount>'

Я пытался сделать IAccountProvider ковариантным, но это, в свою очередь, сильно ограничивает меня в использовании интерфейса ...

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

static int Main(string[] args)
{
    var jiraProv = new JiraProvider();
    //var someList = new List<IAccountProvider<OAuthAccount>>();  // this would work - but it's not what I want...
    var someList = new List<IAccountProvider<IAccount>>();  // this doesn't seem to work
    someList.Add(jiraProv);     // error CS1503 cannot convert from X to Y
    return 0;
}

//-----------------
// Interfaces - details left out for brevity...
// Providers
public interface IAccountProvider<T>
    where T : IAccount
{
    List<T> Accounts { get; }
    T CurrentAccount { get; }
    void Login(T account);
}

public interface IOAuthProvider<T> : IAccountProvider<T>
    where T : IOAuthAccount
{ }

// Accounts
public interface IAccount { }
public interface IOAuthAccount : IAccount { }

//-----------------
// Implementations - details left out for brevity...
public class OAuthAccount : IOAuthAccount { }
public class JiraProvider : IOAuthProvider<OAuthAccount>
{
    public List<OAuthAccount> Accounts { get; set; }
    public OAuthAccount CurrentAccount { get; set; }
    public void Login(OAuthAccount account) { }
}
...