是否可以为存储库模式提供强类型的类?

时间:2019-07-07 13:37:53

标签: c#

我正在尝试实现存储库模式,但是当实体具有不同类型的ID时,我不明白它怎么可能。目前,我必须回退到使用对象,而我真的想使用存储库所持有实体的ID的特定类型。

const path = require('path');
const webpack = require('webpack');
const pkg = require('./package.json');
const fs = require('fs');

const banner = `${pkg.name} - ${pkg.version} - (c) 2017 - ${pkg.author} - ${pkg.homepage} \n\n ${fs.readFileSync('LICENSE').toString()}`;

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, './awsdk_module/lib/'),
    filename: 'awsdk.js',
    library: 'awsdk',
    libraryTarget: 'umd',
    umdNamedDefine: true,
  },
  devtool: 'source-map',
  module: {
    noParse: [/dtrace-provider$/, /safe-json-stringify$/, /mv/],
    rules: [
      {
        test: /\.js$/,
        include: path.join(__dirname, './src/awsdk'),
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.js$/,
        include: path.join(__dirname, './specs'),
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
    ],
  },
  node: {
    console: false,
    fs: 'empty',
    net: 'empty',
    module: 'empty',
    tls: 'empty',
  },
  devServer: {
    contentBase: path.join(__dirname, './specs'),
    inline: true,
    port: 8081,
  },
  plugins: [
    new webpack.BannerPlugin(banner),
  ],
};

我也尝试过类似的事情:

interface IEntity
{
    object GetId();
}

class Foo : IEntity
{
    private string id;

    public Foo(string id)
    {
        this.id = id;
    }

    public object GetId()
    {
        return id;
    }
}

class Bar : IEntity
{
    private int id;

    public Bar(int id)
    {
        this.id = id;
    }

    public object GetId()
    {
        return id;
    }
}

class Repository<T> where T : IEntity
{
    private Dictionary<object, T> entities = new Dictionary<object, T>();

    public IEnumerable<T> List => entities.Values.AsEnumerable();

    public void Add(T entity)
    {
        entities.Add(entity.GetId(), entity);
    }

    public T Get(object id)
    {
        return entities[id];
    }
}

class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo("0");

        var bar = new Bar(0);

        var fooRepo = new Repository<Foo>();
        fooRepo.Add(foo);
        fooRepo.Get(foo.GetId());

        var barRepo = new Repository<Bar>();
        barRepo.Add(bar);
        barRepo.Get(bar.GetId());
    }
}

2 个答案:

答案 0 :(得分:1)

您可以将密钥的通用类型添加到IEntity。例如,

interface IEntity<TId>
{
    TId GetId();
}

class Foo : IEntity<string>
{
    private string id;

    public Foo(string id)
    {
        this.id = id;
    }

    public string GetId()
    {
        return id;
    }
}

class Repository<TEntity, TId> where TEntity : IEntity<TId>
{
    private Dictionary<TId, TEntity> entities = new Dictionary<TId, TEntity>();

    public void Add(TEntity entity)
    {
        entities.Add(entity.GetId(), entity);
    }

    public TEntity Get(TId id)
    {
        return entities[id];
    }
}

答案 1 :(得分:0)

Joel的解决方案可以扩展为允许变化。通用集合以同样的方式实现IEnumerableIEnumerable<T>

实体

interface IEntity
{
    object GetId();
}

interface IEntity<TId> : IEntity
{
    new TId GetId();
}

abstract class EntityBase<TId> : IEntity<TId>
{
    protected TId id;

    protected EntityBase(TId id)
    {
        this.id = id;
    }

    public TId GetId() => id;

    object IEntity.GetId() => GetId();
}

存储库

abstract class Repository
{
    protected Dictionary<object, IEntity> entities;

    protected Repository()
    {
        entities = new Dictionary<object, IEntity>();
    }

    public virtual void Add(IEntity entity) 
    {
        if (entity == null) throw new ArgumentNullException(nameof(entity));
        entities.Add(entity.GetId(), entity);
    }

    public virtual IEntity Get(object id)
    {
        if (id == null) throw new ArgumentNullException(nameof(id));
        return entities[id];
    }
}

abstract class Repository<TId, TEntity> : Repository 
    where TEntity : class, IEntity<TId>
{
    protected Repository() : base() { }

    public override void Add(IEntity entity)
    {
        Add((TEntity)entity);
    }

    public override IEntity Get(object id)
    {
        return Get((TId)id);
    }

    public void Add(TEntity entity)
    {
        if (entity == null) throw new ArgumentNullException(nameof(entity));
        entities.Add(entity.GetId(), entity);
    }

    public TEntity Get(TId id)
    {
        if (id == null) throw new ArgumentNullException(nameof(id));
        return (TEntity)entities[id];
    }
}

用例

class Foo : EntityBase<string>
{
    public Foo(string id) : base(id) { }
}

class Bar : EntityBase<int>
{
    public Bar(int id) : base(id) { }
}

class FooRepository : Repository<string, Foo>
{
    public FooRepository() { }
}

class BarRepository : Repository<int, Bar>
{
    public BarRepository() { }
}

测试

[TestMethod]
public void IEntitySupport()
{
    // use IEntity and object
    IEntity bar = new Bar(1);
    Repository barRepository = new BarRepository();
    barRepository.Add(bar);
    var bar2 = barRepository.Get((object)1);
    Assert.AreSame(bar, bar2);
}

[TestMethod]
public void TEntitySupport()
{
    // use TEntity and TId
    var foo = new Foo("a");
    var fooRepository = new FooRepository();
    fooRepository.Add(foo);
    var foo2 = fooRepository.Get("a");
    Assert.AreSame(foo, foo2);
}