|
ms
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Generics and casting<root> <Account> <Id>1</Id> <Name>Somename</Name> <City>Somecity</City> <ContactPersons> <ContactPerson> <Id>1</Id> <Name>Somename</Name> </ContactPerson> <ContactPerson> <Id>2</Id> <Name>Somename2</Name> </ContactPerson> </ContactPersons> </Account> </root> I created a generic businesscollection (named BusinessCollection) and a business class (named BusinessObject). Then I created a specific business class named Account en another one called ContactPerson. They both derive from the BusinessObject class. I created a instance of a businesscollection with accounts using: BusinessCollection <Account> collection = new BusinessCollection <Account>(); I also made a parser that 'translates' the xml into the correct business classes. So in case of the data above I provide a instance of BusinessCollection <Account>. Then I create Account objects and add them to the collection. This is all done using reflection and some XPath classes. The parser has the folling method signature: public static void ParseToBusinessObjects <T>(BusinessCollection <T> collection, XPathDocument document) where T : BusinessObject So far so good. But now I also want subcollections to parse. In the xml data ContactPersons will be my subcollection (property is named the same). If my parser detects a subcollection it will get the current instance (using reflection). I then want to call my entry method again for this collection (recursive) However when I do this: BusinessCollection <BusinessObject> subCollection = (BusinessCollection <BusinessObject>) property.GetValue(instance, null); I get a InvalidCastException saying I can't convert between a BusinessCollection<ContactPerson> and a BusinessCollection<BusinessObject>. Its the same when I change it to : BusinessCollection <T> subCollection = (BusinessCollection <T>) property.GetValue(instance, null); I hope someone knows how to solve this because its driving me nuts. Alexander van Doormalen wrote:
Show quoteHide quote > I have a xml file with data from various sources. For example: This isn't supported. It's called covariance, and that's not supported> > <root> > <Account> > <Id>1</Id> > <Name>Somename</Name> > <City>Somecity</City> > <ContactPersons> > <ContactPerson> > <Id>1</Id> > <Name>Somename</Name> > </ContactPerson> > <ContactPerson> > <Id>2</Id> > <Name>Somename2</Name> > </ContactPerson> > </ContactPersons> > </Account> > </root> > > I created a generic businesscollection (named BusinessCollection) and > a business class (named BusinessObject). Then I created a specific > business class named Account en another one called ContactPerson. They > both derive from the BusinessObject class. > > I created a instance of a businesscollection with accounts using: > BusinessCollection <Account> collection = new BusinessCollection > <Account>(); > > I also made a parser that 'translates' the xml into the correct > business classes. So in case of the data above I provide a instance of > BusinessCollection <Account>. Then I create Account objects and add > them to the collection. This is all done using reflection and some > XPath classes. > > The parser has the folling method signature: > public static void ParseToBusinessObjects <T>(BusinessCollection <T> > collection, XPathDocument document) where T : BusinessObject > > So far so good. But now I also want subcollections to parse. In the > xml data ContactPersons will be my subcollection (property is named > the same). If my parser detects a subcollection it will get the > current instance (using reflection). I then want to call my entry > method again for this collection (recursive) > > However when I do this: > BusinessCollection <BusinessObject> subCollection = > (BusinessCollection <BusinessObject>) property.GetValue(instance, > null); > > I get a InvalidCastException saying I can't convert between a > BusinessCollection<ContactPerson> and a > BusinessCollection<BusinessObject>. > > Its the same when I change it to : > BusinessCollection <T> subCollection = (BusinessCollection <T>) > property.GetValue(instance, null); in .NET generics. BusinessCollection<BusinessObject> isn't a supertype of BusinessCollection<Contact>, even though it might look like it. That's why casts fail. You can solve it easily though. Implement an interface. Interfaces are a general way to do generic programming if the generic type descriptor changes. So, on your BusinessCollecttion<T>, you implement IBusinessCollection. That's a non-generic interface, with the same methods. You can now do: IBusinessCollection subCollection = (IBusinessCollection)property.Getvalue(instance, null); and call your code again. Frans -- ------------------------------------------------------------------------ Lead developer of LLBLGen Pro, the productive O/R mapper for .NET LLBLGen Pro website: http://www.llblgen.com My .NET blog: http://weblogs.asp.net/fbouma Microsoft MVP (C#) ------------------------------------------------------------------------ Frans Bouma [C# MVP] <perseus.usenetNOSPAM@xs4all.nl> wrote:
> > Its the same when I change it to : Just a tiny correction - it's not supported in C# generics. Apparently > > BusinessCollection <T> subCollection = (BusinessCollection <T>) > > property.GetValue(instance, null); > > This isn't supported. It's called covariance, and that's not supported > in .NET generics. BusinessCollection<BusinessObject> isn't a supertype > of BusinessCollection<Contact>, even though it might look like it. > That's why casts fail. ..NET itself supports both covariance and contravariance, but C# doesn't expose it. See the following link for details - it's fascinating stuff... http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too To bad thats not possible yet :(. I hope it will be in the feature.
Since using interfaces isn't possibe because of various reasons (like internal methods that need to be called on the object etc). So I 'solved' it by creating an internal method that expects a plain object. I then use reflection to call the Add method on that collection (which is passed as an object) MethodInfo info = collection.GetType().GetMethod("Add"); object[] paramaters = new object[1]; paramaters[0] = businessObject; info.Invoke(collection, paramaters); Not a very clean way but it works for now. Thnx guys for the help! Alexander van Doormalen <avdoorma***@gmail.com> wrote:
Show quoteHide quote > To bad thats not possible yet :(. I hope it will be in the feature. Why not still use interfaces, but then cast in the code which "knows > > Since using interfaces isn't possibe because of various reasons (like > internal methods that need to be called on the object etc). So I > 'solved' it by creating an internal method that expects a plain object. > I then use reflection to call the Add method on that collection (which > is passed as an object) > > MethodInfo info = collection.GetType().GetMethod("Add"); > object[] paramaters = new object[1]; > paramaters[0] = businessObject; > > info.Invoke(collection, paramaters); > > Not a very clean way but it works for now. better"? It's not great, but it's better than reflection... -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too Will look into that when I've got some time again. Thnx for the
suggestions. Alexander van Doormalen wrote:
Show quoteHide quote > To bad thats not possible yet :(. I hope it will be in the feature. You can also use an internal interface and implement it explicitly.> > Since using interfaces isn't possibe because of various reasons (like > internal methods that need to be called on the object etc). So I > 'solved' it by creating an internal method that expects a plain > object. I then use reflection to call the Add method on that > collection (which is passed as an object) > > MethodInfo info = collection.GetType().GetMethod("Add"); > object[] paramaters = new object[1]; > paramaters[0] = businessObject; > > info.Invoke(collection, paramaters); > > Not a very clean way but it works for now. Then, cast to the interface as Jon explained. I do that too for internal methods on my generic collections, works like a charm. so: internal interface IFoo { void MyInternalMethod(); } public class BusinessCollection<T>: IFoo { void IFoo.MyInternalMethod() { //... } } IFoo foo = (IFoo)myCollection; foo.MyInternalMethod(); FB -- ------------------------------------------------------------------------ Lead developer of LLBLGen Pro, the productive O/R mapper for .NET LLBLGen Pro website: http://www.llblgen.com My .NET blog: http://weblogs.asp.net/fbouma Microsoft MVP (C#) ------------------------------------------------------------------------ Then I need 2 interfaces as I have both internal and public methods.
Will give it some thought. I added some interfaces but still the same casting problem.
Unable to cast object of type 'BusinessCollection`1[ContactPerson]' to type 'IBusinessCollection`1[IBusinessObject]'. OR Unable to cast object of type 'BusinessCollection`1[ContactPerson]' to type 'BusinessCollection`1[IBusinessObject]'. Some details: - public interface IBusinessCollection<T> where T: IBusinessObject - public interface IBusinessObject - public class BusinessCollection<T> : Collection <T>, ICollection <T>, IBusinessCollection<T> where T: IBusinessObject - public class User: BusinessObject, IBusinessObject - public class ContactPerson: BusinessObject, IBusinessObject - Property inside User class: public BusinessCollection <ContactPerson> ContactPersons { get { return this.contactPersons; } } Am I doing something completely wrong or... Alexander van Doormalen <avdoorma***@gmail.com> wrote:
> I added some interfaces but still the same casting problem. I was talking about casting (on a single element - not the collection) > > Unable to cast object of type 'BusinessCollection`1[ContactPerson]' to > type 'IBusinessCollection`1[IBusinessObject]'. > > OR > > Unable to cast object of type 'BusinessCollection`1[ContactPerson]' to > type 'BusinessCollection`1[IBusinessObject]'. whenever you needed to use a member of the concrete class which isn't present in the interface. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too Ok my mistake. I though you guys ment using an interface element would
solve the inherritance problem. But you where only focussing on the reflection call :) Then I will just go back to passing it as an object to the method instead of a businesscollection type. Only without the reflection method call. Thnx! This will do I guess Jon Skeet [C# MVP] wrote:
Show quoteHide quote > Frans Bouma [C# MVP] <perseus.usenetNOSPAM@xs4all.nl> wrote: Thanks, Jon :)> > > Its the same when I change it to : > > > BusinessCollection <T> subCollection = (BusinessCollection <T>) > > > property.GetValue(instance, null); > > > > This isn't supported. It's called covariance, and that's not > > supported in .NET generics. BusinessCollection<BusinessObject> > > isn't a supertype of BusinessCollection<Contact>, even though it > > might look like it. That's why casts fail. > > Just a tiny correction - it's not supported in C# generics. > Apparently .NET itself supports both covariance and contravariance, > but C# doesn't expose it. See the following link for details - it's > fascinating stuff... > > http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx FB -- ------------------------------------------------------------------------ Lead developer of LLBLGen Pro, the productive O/R mapper for .NET LLBLGen Pro website: http://www.llblgen.com My .NET blog: http://weblogs.asp.net/fbouma Microsoft MVP (C#) ------------------------------------------------------------------------
AppDomains and Exceptions
String concatenation -- not the typical question How properly return XML from an ASPX page? Connection pooling problem testing internet connectin Why can't my delegate be public? authorization problem Visual studio guide ? how to set proxy programmatically Studio versions & development |
|||||||||||||||||||||||