问题
I have the following class
public class AccountingBase<TItemType> where TItemType : AccountingItemBase
And in my AccountingItemBase i have the following property:
public virtual AccountingBase<AccountingItemBase> Parent { get; set; }
in my AccountingBase, I am trying to do the following
item.Parent = this;
Logically this should work, as TItemType inherits from AccountingItemBase, but instead i get the following error:
> Error 1 Cannot implicitly convert type
> 'TGS.MySQL.DataBaseObjects.AccountingBase<TItemType>'
> to
> 'TGS.MySQL.DataBaseObjects.AccountingBase<TGS.MySQL.DataBaseObjects.AccountingItemBase>'
How can i set the child properties parent property to itself (inside the parent class)
回答1:
No, your intuition is incorrect. It shouldn't work, because generic classes aren't variant in .NET.
Just because TItemType
inherits from AccountingItemBase
doesn't mean that AccountingBase<TItemType>
inherits from AccountingBase<AccountingItemBase>
. Suppose AccountingBase<TItemType>
had a field of type TItemType
. Then if your intuition were correct, you could write:
AccountingBase<SomeSubtype> x = new AccountingBase<SomeSubtype>();
AccountingBase<AccountingItemBase> y = x;
y.SomeField = new OtherSubtype();
That would clearly break type safety, because when looked at as an AccountingBase<SomeSubtype>
, the field is meant to be of type SomeSubtype
, but you've put a value of type OtherSubtype
in there!
Basically, generic variance is a complex topic.
I suggest you read Eric Lippert's long and detailed blog post series for more information. Or I have a video from NDC 2010 which you may find useful. Basically in .NET 4 there's some generic variance, but it's limited.
Now, as to what you can do in your situation:
- You could create a nongeneric base class which
AccountingBase
inherits from. That's probably the best idea. Then make the type of theParent
property that nongeneric type. - You could make
AccountingBase
generic in both itself and its parent... but that ends up causing recursion issues, effectively...
回答2:
In addition to Jon's options, you could:
Create an interface
IAccountingBase
that provides only the limited access required by AccountingItemBase to do its work (similar to a non-generic base class, but further abstracted.)Restructure your code so that AccountingItemBase doesn't need a Parent reference to do its work. My experience has been that circular dependencies (Owner knows about Items which know about Owner) are symptomatic of a design where the Child instances are taking on too many responsibilities. You can sometimes get around this by moving the functionality to the Parent or by moving it to higher-level classes that perform complex operations on multiple Items in the context of a single Parent, eliminating the need for each Item to have a Parent reference. For instance, if your Items expose functions related to Account reconciliation, you might have an AccountReconciler class rather than putting the functions on the Items.
来源:https://stackoverflow.com/questions/4043702/c-sharp-generics-inheritance