Реализация фабрики с универсальным интерфейсом - PullRequest
0 голосов
/ 10 декабря 2018

Я абстрагирую зависимости от контрактов, чтобы отделить зависимости

// Abstraction -- This can be published as contract where implementation needs to implement method. Most importantly 3rd party types are not present/tied to contract

public interface ISourceFactory {
   T GetSource<T>();
}


// Implementation which depends on specific source like 3rd party

public class SourceFactory {
    public T GetSource<T>()   //Unable to make this work
    {
        Type listType = typeof(T);
        if (listType == typeof(SomeBase))
        {
            return _connection.GetSource<T>();
        }
        if(listType == typeof(ExternalBase)){
            return _exconnection.GetSource<T>();
        }
        throw new Exception("Not supported");
    }

    private Connection _connection;
    private ExternalConnection _exconnection;
}

// 3rd party implementation
public class Connection {
    public T GetSource<T> where T : SomeBase
}

// 3rd party implementation
public class ExternalConnection {
    public T GetSource<T> where T : ExternalBase
}

Однако я не могу заставить SourceFactory.GetSource работать, так как он выводит, что T нельзя использовать в качестве универсального параметра.

Кто-нибудь может подсказать, каков общий подход к этой проблеме?

Ответы [ 2 ]

0 голосов
/ 10 декабря 2018

Вы должны использовать отражение для этого.Наиболее удобный способ, если с отражением вообще существует что-то вроде удобства, - это использовать универсальные типы, то есть MakeGenericType и привести результат соответствующим образом.Это также имеет то преимущество, что вы выполняете проверки только один раз для каждого типа.

public class SourceFactory {
    private class SourceGetter<T> {
        public static readonly SourceGetter<T> Instance;
        static SourceGetter() {
            Type listType = typeof(T);
            if (listType == typeof(SomeBase))
            {
                Instance = (SourceGetter<T>)Activator.CreateInstance(typeof(CollectionGetter<>).MakeGenericType(listType));
            }
            else if(listType == typeof(ExternalBase)){
                Instance = ...            }
            else {
                Instance = new SourceGetter<T>();
            }
        }
        public virtual T GetSource(SourceFactory sourceFactory) {
            throw new Exception();
        }
    }
    private class CollectionGetter<T> : SourceGetter<T> where T : SomeBase {
        public override T GetSource(SourceFactory sourceFactory) {
            return sourceFactory._connection.GetSource<T>();
        }

    }
    ...
    public T GetSource<T>()
    {
        return SourceGetter<T>.Instance.GetSource(this);
    }

    private Connection _connection;
    private ExternalConnection _exconnection;
}

Редактировать: Изменен код, чтобы его было легче расширять.

0 голосов
/ 10 декабря 2018

Как сказано в комментариях, это само по себе невозможно, потому что соединения должны иметь что-то общее, чтобы их можно было абстрагировать как общие.Вы используете сторонние компоненты, но, поскольку вы пытаетесь использовать их на одной фабрике, я полагаю, что вы хотите получить от них одинаковые данные.Поэтому я предлагаю определить интерфейс, в котором вы определяете общую часть, которая вам нужна:

public interface IConnection{
string GetConnectionString();
...
}

Чем вы оборачиваете свои соединения сторонней организации:

public class SomebaseWrapper : IConnection{
public SomebaseWrapper(SomeBase b){
}
...
}

Чем вы запрашиваете обертку вваша фабрика:

public interface ISourceFactory {
   T GetSource<T>() where T is IConnection;
}

И, наконец, вы запрашиваете SomebaseWrapper и реализуете его так:

public T GetSource<T>() where T : IConnection
        {
            Type listType = typeof(T);
            if (listType == typeof(SomebaseWrapper))
            {
                return new SomebaseWrapper(_connection.GetSource<SomeBase>());
            }
            if (listType == typeof(ExternalBaseWrapper))
            {
                return new (ExternalBaseWrapper)(_exconnection.GetSource<T>());
            }
            throw new Exception("Not supported");
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...