我一直致力于从我的应用程序中删除大量代码重复,特别是在我的模型周围。几个模型还有一个集合变体,它是模型类型的IEnumerable。以前所有的集合变体都是单独的实现,但我能够将其大部分代码组合到一个ModelCollection基类中。
现在,在这些集合模型之上是具有分页值的其他模型,它们都具有完全相同的属性,因此我还希望将它们合并到基类中。我遇到的问题是.NET不支持多继承,并且因为每个ModelCollection实现仍然需要显式实现,因为大多数都有一些特殊的逻辑,一个简单的通用链不会解决问题也是。
ModelCollection基类:
public abstract class ModelCollection<TModel> : IEnumerable<T>, IModel where TModel : IPersistableModel
{
protected readonly List<TModel> Models;
protected ModelCollection()
{
Models = new List<TModel>();
}
protected ModelCollection(params TModel[] models)
: this((IEnumerable<TModel>)models)
{
}
protected ModelCollection(IEnumerable<TModel> models)
: this()
{
models.ForEach(Models.Add);
}
public virtual int Count
{
get { return Models.Count; }
}
public virtual IEnumerator<TModel> GetEnumerator()
{
return Models.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public virtual void Add(TModel model)
{
Models.Add(model);
}
public virtual void Accept(Breadcrumb breadcrumb, IModelVisitor visitor)
{
foreach (var model in this)
{
model.Accept(breadcrumb.Attach("Item"), visitor);
}
visitor.Visit(breadcrumb, this);
}
public bool IsSynchronized { get; set; }
}
PagedCollection的示例:
public class PagedNoteCollection : NoteCollection
{
public PagedNoteCollection(params Note[] notes)
: base(notes)
{
}
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
public int TotalNotesCount { get; set; }
}
IModel接口供参考:
public interface IModel
{
void Accept(Breadcrumb breadcrumb, IModelVisitor visitor);
}
答案 0 :(得分:0)
使用Castle.DynamicProxy及其Mixins功能可以解决此问题。
首先,ModelCollection基类需要有一个接口,在这个特定的例子中,由于实现只是IModel和IEnumerable接口的组合,它只需要继承这些接口:
public interface IModelCollection<T> : IEnumerable<T>, IModel
{
}
其次,您需要一个接口和一个实现来表示分页字段:
public interface IPagingDetails
{
int CurrentPage { get; set; }
int TotalPages { get; set; }
int TotalCount { get; set; }
bool HasPreviousPage { get; }
int PreviousPage { get; }
bool HasNextPage { get; }
int NextPage { get; }
}
public class PagingDetails : IPagingDetails
{
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
public int TotalCount { get; set; }
public bool HasPreviousPage
{
get { return CurrentPage > 1; }
}
public int PreviousPage
{
get { return CurrentPage - 1; }
}
public bool HasNextPage
{
get { return CurrentPage < TotalPages; }
}
public int NextPage
{
get { return CurrentPage + 1;}
}
}
接下来,为了在生成代理后简化对各个部分的访问(特别是删除在ModelCollection和PagingDetails接口之间转换代理的要求),我们需要一个空接口来组合分页和集合接口:
public interface IPagedCollection<T> : IPagingDetails, IModelCollection<T>
{}
最后,我们需要创建具有分页详细信息的代理作为mixin:
public class PagedCollectionFactory
{
public static IPagedCollection<TModel> GetAsPagedCollection<TModel, TCollection>(int currentPage, int totalPages, int totalCount, TCollection page)
where TCollection : IModelCollection<TModel>
where TModel : IPersistableModel
{
var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions();
options.AddMixinInstance(new PagingDetails { CurrentPage = currentPage, TotalPages = totalPages, TotalCount = totalCount });
return (IPagedCollection<TModel>)generator.CreateClassProxyWithTarget(typeof(TCollection), new[] { typeof(IPagedCollection<TModel>) }, page, options);
}
}
现在我们可以使用代理(这取自我写的单元测试以确保它有效):
var collection = new NoteCollection(
new Note {Text = "note 1"},
new Note {Text = "note 2"},
new Note {Text = "note 3"},
new Note {Text = "note 4"});
var pagedCollection = PagedCollectionFactory.GetAsPagedCollection<Note,NoteCollection>(1, 1, 1, collection);
Assert.That(pagedCollection.CurrentPage, Is.EqualTo(1));
Assert.That(pagedCollection.ToList().Count, Is.EqualTo(4));