动态调用类

时间:2018-10-05 18:21:13

标签: c# oop .net-core

让我们假设我有两个提供商提供的两个相同的服务,并且我想编写一个根据客户端请求调用其中一个的代码。

更清楚地说,我有提供者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 :(得分:1)

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");
    }
}

希望这会有所帮助。

答案 1 :(得分:0)

使用DI来避免ProvidersManager中的更改。

或者您也可以重构此代码并创建一个工厂,该工厂可以负责为提供的提供程序名称提供提供类型的对象。

答案 2 :(得分:0)

您可以使用一些替代方法来完成此任务:

通用类型

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");

答案 3 :(得分:0)

更改以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时,请检查Service lifetimes

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IProviderInterface, ProviderA>();
}

答案 4 :(得分:0)

如果您确实不想在添加新提供程序时更改代码,那么您可以使用使用引用

Type providerType = Type.GetType("Provider" + ProviderName);
ProviderObj = (IProviderInterface)Activator.CreateInstance(providerType);