Generics - How to ctype an instance of a generic class to something that I can use

A

Andrew Backer

I hope someone out there can help me with this, because I am stuck.

My problem is that I have an instance of a generic class, but I don't know
ahead of time what the type parameter used was. In my case the type must
derive from a class, like UserControl, so I at least know I should be able
to use that.

I can not figure out a way to get this as an instance of the generic class,
but with the base class as the type parameter. I am looking to do something
like this :

...Dim formRef as Form = /get-reference-to-mycontainer-instance/
...If ( TypeOf formRef Is MyContainer(Of UserControl) ) Then
....... Dim a As MyContainer(Of UserControl) = CType(formRef, MyContainer(Of
UserControl))
....... do stuff
...End If

Here is the generic class:
-------
...Public Class MyContainer(Of T As {UserControl, New})
.......Inherits System.Windows.Forms.Form
.......
...End Class


Is there any way to do something like this? Even something ugly?

Thanks,
//Andrew
 
J

Jon Skeet [C# MVP]

<Andrew Backer
I hope someone out there can help me with this, because I am stuck.

My problem is that I have an instance of a generic class, but I don't know
ahead of time what the type parameter used was. In my case the type must
derive from a class, like UserControl, so I at least know I should be able
to use that.

I can not figure out a way to get this as an instance of the generic class,
but with the base class as the type parameter.

You can't - generics don't support covariance/contravariance. So, for
example, a List<string> isn't compatible with List<object>. In
particular, imagine what would happen if you tried to add a new plain
object to it...

See Eric Lippert's blog for more information on this:

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravar
iance/default.aspx
 
A

Andrew Backer

Actually, I do read his blog, one of the few from MS. It usually hurts my
brain, and the sense it makes is only flitting. I went back and read the
ones that I thought might be relevant, and here is his quote:

//Why is this broken? Because it should always be legal to put a Turtle into
an array of Animals. With array covariance in the language and runtime you
cannot guarantee that an array of Animals can accept a Turtle (animal->reptile->tutrle)
because the backing store might actually be an array of Giraffes (animal->mamal->giraffe).
// Parens are mine.

So basically, I have this _thing_, and there is nothing anywhere that I can
convert it to in order to call methods on it. I can't convert it to the
base class, and call base class methods. I recognize the similarity, but
something in me won't see why it is the same case. Is it not allowed because,
somehow at some point I could write to that object (which I used the generic
for) with a type that would be contravaint?, ie, I could theoretically try
to write a turtle into my giraffe, and the compiler can't tell that I am
not going to do that, so it just doesn't allow the conversion at all?

Sorry for the muddled thought. It makes sense just enough that I get it,
but I can't write it properly. In any case, I am not doing any thing dangerious
in this class, the only New or assignment happens in the constructor basically,
but the compiler can't guarantee that will be the case in the future. Arg.

I read I can do it by poking at Ms.Vb.CompilerServices.Conversions, but I
don't think thats a good idea.


Thanks for the re-pointer =)

//Andrew
 
J

Jon Skeet [C# MVP]

Andrew Backer said:
Actually, I do read his blog, one of the few from MS. It usually hurts my
brain, and the sense it makes is only flitting.

I know what you mean. He's clearly a very smart cookie though - I'm
glad it's him and not me that has to work these things out :)
So basically, I have this _thing_, and there is nothing anywhere that I can
convert it to in order to call methods on it. I can't convert it to the
base class, and call base class methods. I recognize the similarity, but
something in me won't see why it is the same case. Is it not allowed because,
somehow at some point I could write to that object (which I used the generic
for) with a type that would be contravaint?, ie, I could theoretically try
to write a turtle into my giraffe, and the compiler can't tell that I am
not going to do that, so it just doesn't allow the conversion at all?

Sort of. It's basically that if you have Foo<T> and Foo<S> and S
derives from T, there's no guarantee that all the operations on Foo<T>
are available on Foo<S>.

However, help is at hand - a generic method may be just what you need.
A VB programmer can give you the VB syntax (I won't even try it -
getting it wrong would be worse than not trying) but if you can make
the method using it generic, you may be able to do something like:

void DoSomething<T>(MyContainer<T> formRef)
where T : UserControl, new()
{
// Now you can do things with formRef
}

<snip>

It may not help, but it just might do...
I read I can do it by poking at Ms.Vb.CompilerServices.Conversions, but I
don't think thats a good idea.

Hmm... it sounds unlikely to me, to be honest. The CLR understands
covariance/contravariance on interfaces, but that's all as far as I'm
aware. Of course, VB could do it all with late binding, but that
doesn't sound like a good idea either.
 
P

Patrice

So you could just use the fact that each element inherits from a user
control to do something such as :

For Each Element As UserControl In formRef
' Do something with Element
Next

without casting the list itself...

You may want to explain your overall goal. For now I'm not sure to see why
you are trying to cast this list. If the problem is to find out what is the
type of an element you could likely expose an ElementType property that
would return this...

--
Patrice


"Andrew Backer" </O=MARINCOUNTY/OU=CIVICCENTER/CN=RECIPIENTS/CN=ABACKER> a
écrit dans le message de (e-mail address removed)...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top