Ninject可以使用匿名委托(func)作为ConstructorArgument吗? [英] Can Ninject use an anonymous delegate (func) as a ConstructorArgument?

查看:284
本文介绍了Ninject可以使用匿名委托(func)作为ConstructorArgument吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个存储库抽象类,其中封装了几乎所有的CRUD功能:

I have a repository abstract class that encapsulates pretty much all of the CRUD functionality:

public abstract class DataRepository<T> : IRepository<T>
    where T : class
{
    public DataContext Context { get; private set; }
    public TransactionScope Transaction { get; private set; }

    /// <summary>
    /// A <see cref="bool"/> function that compares the keys for fetching a single item, for example: 
    /// return item1.Id == item2.Id (as an anonymous delegate).
    /// </summary>
    public Func<T, T, bool> KeyCompare { get; private set; }

    /// <summary>
    /// Creates a new data repository.
    /// </summary>
    /// <param name="context"></param>
    /// <param name="scope"></param>
    /// <param name="keyCompare">
    /// A <see cref="bool"/> function that compares the keys for fetching a single item, for example: 
    /// return item1.Id == item2.Id (as an anonymous delegate).
    /// </param>
    public DataRepository(DataContext context, TransactionScope scope, Func<T, T, bool> keyCompare)
    {
        Context = context;
        Transaction = scope;
        KeyCompare = keyCompare;
    }

    public virtual T Item(T item)
    {
        return Items().SingleOrDefault(e => KeyCompare(e, item));
    }

    public virtual IEnumerable<T> Items()
    {
        return DataTable.AsEnumerable();
    }

    protected virtual Table<T> DataTable { get { return Context.GetTable<T>(); } }

    /// <summary>
    /// A method that updates the non-key fields of an existing entity with those of specified <see cref="item"/>.
    /// Called by the <see cref="Save"/> method.
    /// </summary>
    /// <param name="existing">The existing record to update.</param>
    /// <param name="item">A <see cref="T"/> object containing the values to update <see cref="existing"/> object with.</param>
    /// <returns></returns>
    protected abstract void UpdateExisting(T existing, T item);

    /// <summary>
    /// A method that updates an existing item or creates a new one, as needed.
    /// </summary>
    /// <param name="item">The entity containing the values to be saved.</param>
    public virtual void Save(T item)
    {
        var existing = Item(item);
        if (existing != null)
        {
            UpdateExisting(existing, item);
        }
        else
        {
            DataTable.InsertOnSubmit(item);
        }

        Context.SubmitChanges();
    }

    /// <summary>
    /// A method that saves all specified items (creates new, updates existing).
    /// </summary>
    /// <param name="items">The entities to be saved.</param>
    public virtual void Save(IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            Save(item);
        }
    }

    /// <summary>
    /// A method that deletes specified item.
    /// </summary>
    /// <param name="item"></param>
    public virtual void Delete(T item)
    {
        var existing = Item(item);
        if (existing != null)
        {
            DataTable.DeleteOnSubmit(existing);
        }

        Context.SubmitChanges();
    }

    public virtual void Delete(IEnumerable<T> items)
    {
        var selection = Items().Where(e => items.Any(item => KeyCompare(e, item)));
        DataTable.DeleteAllOnSubmit(selection);

        Context.SubmitChanges();
    }
}

KeyCompare属性在派生类中的用法与此类似,因此基类知道如何隔离存储库中的单个项目(并非所有实体"都具有"Id"属性,并且某些键跨越多个列-此解决方案尝试解决该特定问题):

The KeyCompare property is used like this in the derived classes, so that the base class knows how to isolate a single item in the repository (not all "entities" have a "Id" property, and some keys span multiple columns - this solution attempts to resolve that particular point):

    public AuthInfoRepository(DataContext context, TransactionScope scope)
        : base(context, scope, (item1, item2) => { return item1.Id == item2.Id;})
    { }

KeyCompare属性实际上是使派生类仅实现UpdateExisting方法的基石,如下所示:

This KeyCompare property is really the cornerstone that allows the derived classes to merely implement the UpdateExisting method, like this:

    protected override void UpdateExisting(AuthInfo existing, AuthInfo item)
    {
        existing.AuthId = item.AuthId;
        existing.ActiveDirectoryGroup = item.ActiveDirectoryGroup;
    }

其余的(实际CRUD)全部由基类处理.使用这个抽象存储库,我已经在几分钟甚至不是几秒钟的时间内实现了具体的存储库,只编写了特定于每个实现的代码.所以干我渴了.

The rest (actual CRUD) is all handled by the base class. With this abstract repository I have been implementing the concrete ones in minutes if not seconds, writing only the code that is specific to each implementation. So DRY I'm thirsty.

DataRepository<T>用于处理SQL Server,因此我还需要另一种模拟实现,我将其称为ListRepository<T>,并且几乎完全相同(除了ContextTransaction属性都返回null).我认为构造函数的签名就是我需要在此处发布的全部内容:

The DataRepository<T> deals with SQL Server, so I needed yet another implementation for mocking, which I've called ListRepository<T> and does pretty much exactly the same thing (except Context and Transaction properties both return null). I think the constructor's signature is all I need to post here:

public ListRepository(IEnumerable<T> items, Func<T, T, bool> keyCompare)

所以现在我准备好进行测试了,我想使用Ninject作为我的IoC容器.我的问题是我似乎无法弄清楚如何将匿名委托作为ConstructorArgument:

So now I'd be ready for testing, and I want to use Ninject as my IoC container. My problem is that I can't seem to figure out how to pass an anonymous delegate as a ConstructorArgument:

Bind<IRepository<AuthInfo>>().To<ListRepository<AuthInfo>>()
                             .WithConstructorArgument("items", _mockAuthInfo)
                             .WithConstructorArgument("keyCompare", ??????);

我想做的事可行还是过于复杂?我不会问它是否是好的/干净的代码,但是在这里欢迎建设性的评论:

Is what I'm trying to do feasible, or just over-complicated? I'm not going to ask if it's good/clean code, but constructive comments are welcome over here:

https://codereview.stackexchange.com/questions/25250 /code-review-for-abstract-repository-implementation

推荐答案

Argh.我讨厌这种情况发生(即在发帖后几分钟找到答案)

Argh. I hate when this happens (i.e. finding the answer minutes after posting)

我所需要的只是一个明确的演员表:

All I needed was an explicit cast:

.WithConstructorArgument("keyCompare", (Func<AuthInfo, AuthInfo, bool>)((item1, item2) => item1.Id == item2.Id));

这篇关于Ninject可以使用匿名委托(func)作为ConstructorArgument吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆