Вызвать класс динамически - PullRequest
0 голосов
/ 05 октября 2018

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

Чтобы быть более понятным, у меня есть провайдер A и провайдерB. Клиент отправит запрос для A или B, поэтому я должен вызвать их классы для обработки запроса.

Я создал интерфейс провайдера

interface IProviderInterface
{
    string GetRedirectUrl();
    string GetStatus();
}

, затем каждый класс провайдерареализовал интерфейс

public class ProviderA: IProviderInterface
{
    public ProviderA()
    {
    }

    public string GetRedirectUrl()
    {
        return "URL for provider A";
    }

    public string GetStatus()
    {
        return "Check status with provider A API";
    }
}

Теперь в классе диспетчера провайдеров я использовал инструкцию switch для вызова нужного класса провайдеров.

public class ProvidersManager
{
    IProviderInterface ProviderObj;

    public ProvidersManager(string ProviderName)
    {
        switch (ProviderName)
        {
            case "A":
                ProviderObj = new ProviderA();
                break;
            case "B":
                ProviderObj = new ProviderB();
                break;
        }
    }

    public string GetRedirectUrl()
    {
        return  ProviderObj.GetRedirectUrl();
    }

    public string GetStatus()
    {
        return ProviderObj.GetStatus();
    }
}

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

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

Ответы [ 5 ]

0 голосов
/ 05 октября 2018

Если вы действительно не хотите менять код при добавлении новых провайдеров, тогда вы используете опцию

Type providerType = Type.GetType("Provider" + ProviderName);
ProviderObj = (IProviderInterface)Activator.CreateInstance(providerType);
0 голосов
/ 05 октября 2018

Изменить конструктор менеджера, который принимает IProviderInterface в качестве параметра.

public class ProvidersManager
{
    IProviderInterface ProviderObj;

    public ProvidersManager(IProviderInterface providerObj)
    {
        ProviderObj = providerObj;
    }

    public string GetRedirectUrl()
    {
        return  ProviderObj.GetRedirectUrl();
    }

    public string GetStatus()
    {
        return ProviderObj.GetStatus();
    }
}

Теперь в вызывающем клиенте передайте экземпляр.

var providerManager = new ProvidersManager(new ProviderA());
var anotherProviderManager = new ProvidersManager(new ProviderB());

или перейдите к DI .Также при использовании DI проверьте Срок службы

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IProviderInterface, ProviderA>();
}
0 голосов
/ 05 октября 2018

Есть несколько альтернатив, которые можно использовать для достижения этой цели:

Универсальный тип

public class ProvidersManager<TProvider> where TProvider : IProviderInterface
{
    public ProvidersManager() =>
       ProviderObj = Activator.CreateInstance<TProvider>();
}

// eg: new ProvidersManager<ProviderA>();

Использование типа (загружается раньше, чем-либо еще)

public ProvidersManager(Type providerImplementationType) =>
    ProviderObj = (IProviderInterface)Activator.CreateInstance(myType);

// eg: new ProvidersManager(typeof(ProviderA));

Использование типаполное имя

public ProvidersManager(string providerFullName) =>
    ProviderObj = (IProviderInterface)Activator.CreateInstance(Type.Load(providerFullName));

// eg: new ProvidersManager("MyApplication.Common.ProviderA");
0 голосов
/ 05 октября 2018

ProviderManager.cs

internal static class ProviderManager
{
    private static readonly Dictionary<string, BaseProvider> _providers = new Dictionary<string, BaseProvider>();

    public static void Register(string name, BaseProvider provider) => _providers.Add(name, provider);
    public static string GetRedirectUrl(string name) => _providers[name].GetRedirectUrl();
    public static string GetStatus(string name) => _providers[name].GetStatus();
}

BaseProvider.cs

internal abstract class BaseProvider
{
    private BaseProvider(string name) => ProviderManager.Register(name, this);  
    public abstract string GetRedirectUrl();
    public abstract string GetStatus();
}

ProviderA.cs

internal class ProviderA : BaseProvider
{
    private readonly string _redirectUrl;
    private readonly string _status;

    public ProviderA(string redirectUrl, string status) : base("A")
    {
        _redirectUrl = redirectUrl
        _status = status;
    }

    public string GetRedirectUrl() => _redirectUrl;
    public string GetStatus() => _status;
}

Использование

internal class Program
{
    public static void Main(string[] args)
    {
        ProviderA providerA = new ProviderA("http://stackoverflow.com", "active");
        string url = ProviderManager.GetRedirectUrl("A");
    }
}

Надеюсь, это поможет.

0 голосов
/ 05 октября 2018

Используйте DI, чтобы избежать изменений в ProvidersManager.

Или вы можете просто реорганизовать этот код и создать фабрику, которая может взять на себя ответственность за предоставление объекта предоставленного типа для предоставленного имени поставщика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...