简体   繁体   English

C#通用类问题

[英]C# Generic Class Question

I am working on a class library and am having some trouble with generics. 我正在开发一个类库,并且在泛型方面遇到了一些麻烦。 I have a ITransaction interface which has a collection of ITransactionItem . 我有一个ITransaction接口,其中包含ITransactionItem的集合。 Each ITranscation can be either a CapitalCall or Distribution . 每个ITranscation可以是CapitalCallDistribution A CapitalCall is a ITransaction but has a few additional properties. CapitalCallITransaction但具有一些其他属性。 A CapitalCallItem is a ITransactionItem with a few additional properties. CapitalCallItem是一个ITransactionItem ,具有一些其他属性。 A CapitalCall has a collection of CapitalCallItems . 一个CapitalCall具有集合CapitalCallItems Likewise, there exists a Distribution class with a collection of DistributionItem . 同样,存在一个带有Distribution集合的DistributionItem

I have tried making the Transaction interface generic: 我尝试使Transaction接口通用:

interface ITransactionBase<TItem> 
    where TItem: ITransactionItem
{
    List<TItem> ITransactionItems
    {
        get;
        set;
    }

}

This works perfectly when I implement it: 当我实现它时,这完美地工作:

class CapitalCall : ITransactionBase<CapitalCallItem>

Now all of the items in the collection are of type CapitalCallItem . 现在,集合中的所有项目都为CapitalCallItem类型。

I run into the following problem. 我遇到以下问题。 I would like to know the associate ITransaction on a ITranscationItem . 我想知道ITranscationItem上的关联ITransaction I created a property on the ITransactionItem table of type ITranscation . 我创建的属性ITransactionItem类型的表ITranscation When I use this property, it is no longer typed to the correct class: 当我使用此属性时,不再将其键入正确的类:

var capitalCall = new CapitalCall();
var trans = capitalCall.TransactionItems[0].Transaction;
// trans is now of the base type ITransaction, instead of typed to CapitalCall.

I have tried making the ITransactionLineItem interface use generics as well, but I get into a recursive generic nightmare when I try to declare it. 我曾尝试使ITransactionLineItem接口也使用泛型,但是当我尝试声明它时,我陷入了递归泛型的噩梦。 What is the correct way to model this? 对此建模的正确方法是什么?

Would this work: 这项工作会:

interface ITransaction<TAction, TItems>
    where TItems : ITransactionItem<TAction, TItems>
    where TAction : ITransaction<TAction, TItems>

interface ITransactionItem<TAction, TItems>
    where TItems : ITransactionItem<TAction, TItems>
    where TAction : ITransaction<TAction, TItems>

I am confused as to how I could then use the interface by itself- what if I want a collection of mixed ITransactionItem , without specifying a type? 我对如何使用接口本身感到困惑-如果我想要混合ITransactionItem的集合而不指定类型怎么办? Also I should add that I have base Transaction / Transaction item classes that implement the interface, and CapitalCall / Dist inherit from. 另外,我还应该补充一点,我具有实现该接口的基本Transaction / Transaction项目类,并且CapitalCall / Dist继承自该类。

Yes, this sort of mutually recursive generic declaration will work, but it will make things very complicated - I know from experience. 是的,这种相互递归的泛型声明可以工作,但是会使事情变得非常复杂-我从经验中知道。 If you want an example of something similar, look at this declaration from my protocol buffers port: 如果您想要一个类似的例子,请从我的协议缓冲区端口查看以下声明

public interface IMessage<TMessage, TBuilder> : IMessage<TMessage>
     where TMessage : IMessage<TMessage, TBuilder> 
     where TBuilder : IBuilder<TMessage, TBuilder>

IBuilder<,> has the equivalent. IBuilder<,>具有等效功能。

This declaration also demonstrates the answer to your last question: if some parts of your interface don't need to know the exact type of transaction, you can declare them in a "less generic" base interface. 该声明还演示回答你的最后一个问题:如果你的界面的某些部分不需要知道交易的确切类型,您可以在“少通用的”基本接口声明它们。 So you could have: 因此,您可以:

interface ITransaction<TAction, TItems> : ITransaction
    where TItems : ITransactionItem<TAction, TItems>
    where TAction : ITransaction<TAction, TItems>

for example, where ITransaction is a non-generic interface. 例如,其中ITransaction是一个非通用接口。

Again though, this is not for the faint of heart. 再说一次,这不是为了胆小者。 In my case I can get away with it because almost no-one uses the raw interfaces - all the implementations are autogenerated, and client code uses those non-generic implementations. 就我而言,我可以避免它,因为几乎没有人使用原始接口-所有实现都是自动生成的,而客户端代码则使用那些非泛型实现。 I would think long and hard before inflicting this on a developer to actually use day to day... 在让开发人员实际使用日常资源之前,我会经过漫长而艰辛的思考。

Yes the interfaces you wrote down should work as far as I can tell. 是的,据我所知,您写下的接口应该可以工作。 Such "recursive" declarations work well with generics, but the question is whether you really need to make those generic in the first place? 这样的“递归”声明与泛型一起使用很好,但是问题是您是否真的需要首先使这些泛型成为现实? Recursive declarations are something which is not often used and may therefore be hard to grasp for other people using your classes. 递归声明是一种不常用的东西,因此对于其他使用您的类的人来说可能很难理解。

As for using the interface for itself, you can still make a less generic interface and also implement it. 至于使用该接口本身,您仍然可以制作一个通用性较低的接口并实现它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM