简体   繁体   English

使用C#Generics的界面设计

[英]Interface design using C# Generics

I am currently designing a class library that will provide data to a web application graph rendering engine in C#. 我目前正在设计一个类库,它将为C#中的Web应用程序图形呈现引擎提供数据。 I am currently defining the interfaces of this library. 我目前正在定义这个库的接口。

I have a IGraphData interface which I would like to cache using a service that accesses the cache, this is called IGraphDataCacheService and has set and get methods to add and retrieve IGraphData objects to and from the cache. 我有一个IGraphData接口,我想使用访问缓存的服务进行缓存,这称为IGraphDataCacheService,并设置和获取方法来向缓存添加和检索IGraphData对象。 the cache service will be a singleton. 缓存服务将是一个单身人士。

I am confused about the correct way to implement this, so that there is only one cache service that can get and set generic IgraphData objects. 我对实现它的正确方法感到困惑,因此只有一个缓存服务可以获取和设置通用IgraphData对象。

I came up with this: 我想出了这个:

interface IGraphDataCacheService {

IGraphData<object> Get(string identifier);
void Set(IGraphData<object> graphData);}

or this: 或这个:

T Get<T, P>(string identifier) where T : IGraphData<P>;
void Set<T,P>(T graphData) where T : IGraphData<P>;

Can any one offer any advice help? 任何人都可以提供任何建议帮助吗?

Thanks 谢谢

Why don't you just make the interface generic instead? 你为什么不把接口变成通用的呢?

interface ICacheService<T> {
    T Get(string identifier);
    void Set(T graphData);
}

if you wanted, you could type-constrain T to be of type IGraphData, or you could write it as: 如果你愿意,你可以键入约束T为IGraphData类型,或者你可以把它写成:

interface IGraphDataCacheService<T> {
    IGraphData<T> Get(string identifier);
    void Set(IGraphData<T> graphData);
}

A few points: 几点:

  1. I'd probably rename the interface methods to be more emblematic of a caching service. 我可能会将接口方法重命名为更具有缓存服务的象征。 For example, Fetch and Store instead of Get and Set , which makes it sound like you're getting or setting the provider rather than the data to be cached. 例如, FetchStore而不是GetSet ,这使得它听起来像您正在获取或设置提供程序而不是要缓存的数据。

  2. Ensuring that there is only one cache is an implementation detail, not an interface one. 确保只有一个缓存是实现细节,而不是接口。

To implement a singleton, try something like: 要实现单例,请尝试以下方法:

public class SingletonCacheService : IGraphDataCacheService {
   private static Singleton instance;

   private Singleton() {}

   // snip implementation of IGraphDataCacheService methods ...

   public static Singleton Instance {
      get {
         if (instance == null) {
            instance = new Singleton();
         }
         return instance;
      }
   }
}

Note that this simple version isn't threadsafe. 请注意,这个简单版本不是线程安全的。

Both alternatives seem plausible at a glance; 两种选择似乎都是合理的; my hunch is that you need to write some 'typical' client code to decide. 我的预感是你需要写一些“典型的”客户代码来决定。 eg Does the typical client 'know' the type of data associated with the identifier it's looking up? 例如,典型客户“知道”与其查找的标识符相关联的数据类型吗? Good API design requires identifying the main use scenarios and using that to inform the design. 良好的API设计需要识别主要使用场景并使用它来通知设计。

If I understand your question correctly you are wanting to treat the generic types like they are the same, but in current .NET implementation you can't do this. 如果我正确理解你的问题,你想要将泛型类型视为相同,但在当前的.NET实现中你不能这样做。

IGraphData<string> can't be passed as a IGraphData<object> they are actually different types even though string is an object, the generic types are not related and can't be cast or passed like they are the same. IGraphData <string>不能作为IGraphData <object>传递它们实际上是不同的类型,即使string是一个对象,泛型类型不相关,也不能像它们一样被强制转换或传递。

If you control the IGraphData interface you can create a IGraphData interface and derive IGraphData from it and use IGraphData to access the cache. 如果您控制IGraphData接口,您可以创建IGraphData接口并从中导出IGraphData并使用IGraphData访问缓存。 It just depends on how you are using it and what you have the control over. 这取决于您如何使用它以及您可以控制的内容。

You can do what you want in C# 4.0. 你可以在C#4.0中做你想做的事。 There is an article about it here 有一个关于它的文章在这里

You can't ensure there's only a single instance implementing an interface. 您无法确保只有一个实例实现接口。 However, you can make a class (eg GraphDataCacheServiceImpl) implementing the interface a singleton by sealing it and providing only a getter property, with the object created as a static variable from a private constructor. 但是,您可以创建一个类(例如GraphDataCacheServiceImpl) 通过密封它并仅提供一个getter属性来实现接口单例,并将对象作为私有构造函数的静态变量创建。 See the below. 见下文。 As far as generics, it's not exactly clear what you're seeking to accomplish. 至于仿制药,你要完成的是什么并不完全清楚。 But I would guess the below is close to what you want. 但我猜想下面的内容接近你想要的。

interface IGraphDataCacheService<T> {

IGraphData<T> Get(string identifier);
void Set(IGraphData<T> graphData);

}


public sealed class GraphDataCacheServiceImpl<T> : IGraphDataCacheService<T>
{

  private GraphDataCacheServiceImpl()
  {
      // ..
  }

  static GraphDataCacheServiceImpl()
  {
    Instance = new GraphDataCacheServiceImpl<T>();
  }

  public IGraphData<T> Get(string id)
  {
      return new GraphDataImpl<T>();
  }

  public void Set(IGraphData<T> graphData)
  {
  }

  public static GraphDataCacheServiceImpl<T> Instance {get; private set;}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM