Can Ninject可以使用匿名委托(func)作为ConstructorArgument吗?

问题描述:

我有一个封装了几乎所有的CRUD功能的资料库抽象类:Can Ninject可以使用匿名委托(func)作为ConstructorArgument吗?

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”属性,有的按键跨越多列 - 该解决方案试图解决特定点):

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

KeyCompare属性是真的,允许得到的基石班级到merel ÿ实施UpdateExisting方法,是这样的:

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

剩余部分(实际CRUD)是全部由基类处理。有了这个抽象的存储库,我已经在几分钟内实现了具体的存储库,如果不是秒,只写出每个实现特有的代码。干我渴了。

DataRepository<T>涉及SQL服务器,所以我还需要为嘲讽另一种实现方式,我已经叫ListRepository<T>并做几乎同样的事情(除了ContextTransaction性能都返回null)。我想构造函数的签名是我需要在这里发布:

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

所以现在我会准备进行测试,我想用Ninject作为我IoC容器。我的问题是,我似乎无法弄清楚如何通过一个匿名委托作为ConstructorArgument

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

是什么,我试图做是可行的,或者只是过于复杂?我不会问,如果是好/干净的代码,但有建设性的意见,欢迎在这里:

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

+0

无法实现equals上的项目?所以你不必传递一个函数呢?或者我在这里错过了什么? – treze

+0

@treze他们是Linq到SQL类,我正在把它们照原样。实现Equals会导致混淆,因为如果要比较关键字段或者比较所有字段并检查是否更新,则无法查看Equals实现。这个想法只是确定关键字段。 –

哎呀。我讨厌当发生这种情况(即发布后找到了答案,分钟)

所有我需要的是一个明确的转换:

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