Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何设置位于通用集合对象之上的通用分页对象?_C#_Generics_Multiple Inheritance_Mixins_Castle Dynamicproxy - Fatal编程技术网

C# 如何设置位于通用集合对象之上的通用分页对象?

C# 如何设置位于通用集合对象之上的通用分页对象?,c#,generics,multiple-inheritance,mixins,castle-dynamicproxy,C#,Generics,Multiple Inheritance,Mixins,Castle Dynamicproxy,我一直在努力从我的应用程序中删除大量重复的代码,特别是在我的模型中。一些模型还有一个集合变量,它是模型类型的IEnumerable。以前所有的集合变体都是单独的实现,但我能够将它们的大部分代码合并到ModelCollection基类中 现在,在这些集合模型之上是具有分页值的其他模型,它们都具有完全相同的属性,因此我还想将它们折叠成一个基类。我遇到的问题是.NET不支持多重继承,而且由于每个ModelCollection实现仍然需要显式实现,因为大多数实现都有一些特殊的逻辑,因此简单的泛型链也不能

我一直在努力从我的应用程序中删除大量重复的代码,特别是在我的模型中。一些模型还有一个集合变量,它是模型类型的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; }
}
IModel接口供参考:

public interface IModel
{
    void Accept(Breadcrumb breadcrumb, IModelVisitor visitor);
}

可以使用Castle.DynamicProxy及其Mixins功能解决此问题

首先,ModelCollection基类需要有一个接口,在这个特定示例中,由于实现只是IModel和IEnumerable接口的组合,它只需要继承这些接口:

public interface IModelCollection<T> : IEnumerable<T>, IModel
{
}
public interface IPagedCollection<T> : IPagingDetails, IModelCollection<T>
{}
其次,您需要一个接口和一个实现来表示分页字段:

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接口之间强制转换代理的要求,我们需要一个空接口来组合paging和collections接口:

public interface IModelCollection<T> : IEnumerable<T>, IModel
{
}
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));

如果您对问题、答案或标题中的措辞有任何改进建议,请毫不犹豫地进行评论或编辑。这是一个如此复杂的问题/解决方案,我想确保一切都非常清楚。