创建一个强制您实现在C#中返回此被调用类的方法的接口或抽象

时间:2016-12-12 07:32:55

标签: c# interface abstract

我试图用C#创建一种ServiceManager。

我希望它有一个set和get函数。

设置签名如下所示:

public void set(string key, ServiceProvider service)

public ServiceProvider get(string key)

我不确定如何写class ServiceProvider

我希望它包含一个返回自己的create方法

例如:

public class SomeService : ServiceProvider
{
    public static SomeService create(ServiceManager serviceManager)
    {
        return new SomeService();
    }
}

另一个例子:

public class SomeOtherService : ServiceProvider
{
    protected FooService fooService;

    public SomeOtherService(FooService fooService)
    {
        this.fooService = fooService;
    }

    public static SomeOtherService create(ServiceManager serviceManager)
    {
        return new SomeOtherService (serviceManager.get("FooService"));
    }
}

如何实施ServiceProvider强迫我编写创建方法?

EDIT1: 我想解释为什么我需要以这种方式构建它。 我的想法是使get方法 lazy ,所以当我通过它的名称调用它时,我才启动实例并将其保存为ServiceManager中的单例。

EDIT2: 这背后的想法是每个实现/继承自ServiceProvider的类都可以按照自己的意愿实现创建。

例如: PlayerService需要在其构造函数中包含数据库适配器。

UtilService在其构造函数中没有参数。

在幕后...... 调用ServiceManager.get(key)时,它会检查实例的字典,如果它不存在,则使用create()方法创建它并将其分配给字典并返回它

最终解决方案:

namespace Infrastructure.Base.Service
{
    public class ServiceManager : Contracts.IServiceManager
    {
        Dictionary<Type, Contracts.IServiceProvider> dictonary;

        public ServiceManager()
        {
            dictonary = new Dictionary<Type, Contracts.IServiceProvider>();
        }

        public Contracts.IServiceProvider get<T>() where T : Contracts.IServiceProvider
        {
            if (!dictonary.ContainsKey(typeof(T)))
            {
                var service = (T)Activator.CreateInstance(typeof(T), this);
                dictonary[typeof(T)] = service;
            } 

            return dictonary[typeof(T)];
        }
    }
}

namespace Infrastructure.Base.Service.Contracts
{
    public interface IServiceProvider
    {
    }
}

namespace Infrastructure.Base.Service.Contracts
{
    public interface IServiceManager
    {
        Infrastructure.Base.Service.Contracts.IServiceProvider get<T>() where T : Infrastructure.Base.Service.Contracts.IServiceProvider;
    }
}

USAGE:

public class PlayerService : IServiceProvider
{
    PlayerAdapter playerAdapter;

    public PlayerService(ServiceManager serviceManager)
    {
        playerAdapter = serviceManager.get<PlayerAdapter>() as PlayerAdapter;
        Debug.Log("I am player service!");
    }
}

public class PlayerAdapter : IServiceProvider
{
    public PlayerAdapter(ServiceManager serviceManager)
    {
        Debug.Log(" I am PlayerAdapter!");
    }
}

void Main()
{
    serviceManager = new ServiceManager();
    PlayerService playerService = serviceManager.get<PlayerService>() as PlayerService;
}

4 个答案:

答案 0 :(得分:3)

您可以为基类执行类似的操作

public abstract class ServiceProvider<T> where T : new()
{
    public static T Create()
    {
        return new T();
    }
}

然后你甚至不需要在派生类中实现Create

public class SomeService : ServiceProvider<SomeService>
{
}

答案 1 :(得分:2)

您无法在C#中覆盖静态方法。静态和虚拟是该语言中的独有术语。

您似乎需要的是一个简单的存储库:

public abstract class ServiceProvider
{

}

public class ServiceManager
{
    private readonly Dictionary<Type, ServiceProvider> repository;

    public ServiceManager()
    {
        repository = new Dictionary<Type, ServiceProvider>();
    }

    public ServiceProvider Get<T>() where T : ServiceProvider
    {
        if (repository.ContainsKey(typeof(T)))
            return repository[typeof(T)];

        var service = (T)Activator.CreateInstance<T>();
        repository[typeof(T)] = service;
        return service;
    }
}

现在实施具体的服务提供商:

public class MyServiceFoo : ServiceProvider
{
    public MyServiceFoo()
    { /*construction logic (your Create()) goes here*/ }
}

public class MyServiceBlah : ServiceProvider
{
    public MyServiceBlah()
    { /*construction logic (your Create()) goes here*/ }
}

并像这样使用它:

var manager = new ServiceManager();
var myFooProvider = manager.Get<MyServiceFoo>();
var myOtherFooProvider = manager.Get<MyServiceFoo>();

var areTheSame = ReferenceEquals(myFooProvider, myOtherFooProvider); //returns true 

<强>更新

如果某些服务提供商在创建时需要参数,那么只需将Get方法更改为以下内容:

public ServiceProvider Get<T>(params object[] args) where T : ServiceProvider
{
    if (repository.ContainsKey(typeof(T)))
        return repository[typeof(T)];

    var service = (T)Activator.CreateInstance(typeof(T), args);
    repository[typeof(T)] = service;
    return service;
}

现在,考虑到您有以下服务:

public class MyServiceBar : ServiceProvider
{
    public MyServiceBar(int myInt)
    { /*construction logic (your Create()) goes here*/ }
}

您只需:

var manager = new ServiceManager();
var myFooProvider = manager.Get<MyServiceFoo>();
var myServiceBar= manager.Get<MyServiceBar>(1);

答案 2 :(得分:0)

据我所知,现在有办法强制实现静态方法。你必须自己照顾这个。 另一种方法是你使你的类通用,在这个类中你有静态创建方法来创建派生对象:

public class ServiceProvider<T>
{
    public static T Create()
    {
        return (T)Activator.CreateInstance(typeof(T));
    }
}

答案 3 :(得分:0)

您出现的问题在软件开发中很常见,但您尝试实施的解决方案并非最佳做法。

我建议像Unity一样使用 IOC (控制容器的反转)。

使用它,您几乎可以配置有关对象生命周期的所有内容(例如,您可以指定是否需要新对象或使用单个实例,等等。)

如果某人(Unity)为您执行此操作,则不应编写代码。

不要遵循涉及反思的解决方案:在我看来,反思是问题的最后解决方案;它在运行时发生,因此您可能会对运行时错误感到惊讶,它不是轻量级操作,并且会损失每个编译时间的好处。

不要使用singleton :它是一个反模式,因为它混淆了2个响应(对象创建和对象生命周期管理)并引入了测试问题。

使用IOC,您可以管理对象的生命周期(如果您想要单个实例,则可以在需要时创建它),并且可以获得可测试性。