开发者

C# Generics and abstract factory pattern - or some way of doing something similar

I am trying to write a sort of extendable data layer for my application One of the "repositories" is an in-memory implementation of my abstract store class

public abstract class Store<TEntity, TIdentifier> : IStore<TEntity, TIdentifier>
        where TEntity : StorableEntity<TIdentifier>        
{
  //abstract methods here

  public abstract TIdentifier GetUniqueIdentifier();
}

The "StorableEntity" abstract class is:

public abstract class StorableEntity<TIdentifier>
{
    public TIdentifier ID { get; set; }
}

I have a concrete class of Store called "InMemoryStore" that looks like this:

public class InMemoryStore<T, U> : Store<T, U>
    where T : StorableEntity<U>
{
    protected static Dictionary<U, T> store = new Dictionary<U, T>();

    public override U GetUniqueIdentifier()
    {
    // call relevant "generator" here - SOMETHING LIKE THIS??
    // var generator = GetGeneratorSomehow(U);
    // return generator.Create();
    }
}

Now, the type of "U" here could be string, int, Guid etc... (most of the time it could be int)

My idea here is to create something like an IUIDGenerator like this:

public interface IUIDGenerator<T&g开发者_StackOverflowt;
{
    T Create(ICollection<T> collection);
}

In the above "InMemoryStore" i would then create an instance of an IUIDGenerator, pass in the store dictionarys key collection, and call the "Create" method to return a unique identifier of the required type.

For example, i could have an IntUIDGenerator class like this (that would act as a kind of incremental number generator, based on the numbers already in the dictionary keys)

public class IntUIDGenerator : IUIDGenerator<int>
{
    public int Create(ICollection<int> collection)
    {
        var result = collection.Max() + 1;
        if (collection.Contains(result))
            return result;

        throw new NotUniqueException();
    }
}

Actual Question: What I need to do, is within InMemoryStore, identify the type of U (the type of the identifier) and be able to dynamically select the required concrete implementation of IUIDGenerator - how can i do this?

I thought about having a type of class factory pattern - loading all the available UIDGenerators into a dictionary... but they can all have different types?

Is there a better way around this?

Also, I am aware the title of my question may be a bit off - if anyone has a better suggestion, please feel free to comment and I'll change it.


You could use an IoC framework, such as Unity, Castle, Ninject, etc. Then you'd configure your container with something like the following:

_container = new UnityContainer();
_container.RegisterType<IUIDGenerator<int>, IntUIDGenerator);
_container.RegisterType<IUIDGenerator<Guid>, GuidUIDGenerator);

Then in your class you've have something like the following:

public override U GetUniqueIdentifier()
{
    var generator = _container.Resolve<IUIDGenerator<U>>();
    return generator.Create();
}


I think you'll have to use at least one cast. If you store all your generators in a map like

Map<Type, object> generators;

you can use

class InMemoryStore<T,U> {
  public override U GetUniqueIdentifier() {
    var generator = generators[typeof(U)] as IUIDGenerator<U>;
    return generator.Create(collection);
  }
}

Of course, I omitted all sort of validation code :) (like checking, if a generator for type U is in the map etc...)


The short answer: Use dependency injection, and let your DI container handle it for you.


You could add an additional generic type argument for the generator, eg

public class InMemoryStore<T, U, V> : Store<T, U>
    where T : StorableEntity<U>
    where V : IUIDGenerator<U>, new() {

    public override U GetUniqueIdentifier()
    {
        return (V)(Activator.CreateInstance<V>()).Create();
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜