469,343 Members | 5,478 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,343 developers. It's quick & easy.

C# typeof() and Generics

Let's say that you have:

class A
{
T DoSomething<T>() where T : class, new()
{
T ThisObj = new T();
// Do something usefull...
return ThisObj;
}

void StartHere(Type type)
{
// And here is the problem
DoSomething<type>();
}
}

Any Ideas on how to call a generic function like 'DoSomething' when the calling function got the type as a parameter, not as a type parameter?

Jorge Varas

Oct 26 '06 #1
12 14492
Let's say that you have:
>
class A
{
T DoSomething<T>() where T : class, new()
{
T ThisObj = new T();
// Do something usefull...
return ThisObj;
}
void StartHere(Type type)
{
// And here is the problem
DoSomething<type>();
}
}
Any Ideas on how to call a generic function like 'DoSomething' when
the calling function got the type as a parameter, not as a type
parameter?
Unfortunately, this can't be done (and I don't see how "typeof" is used here).
The closest that you could get is to make the StartHere method generic like
this:

class A
{
T DoSomething<T>() where T : class, new()
{
T ThisObj = new T();
// Do something usefull...
return ThisObj;
}

void StartHere<T>()
{
// And here is the problem
T myValue = DoSomething<T>();
}
}

Best Regards,
Dustin Campbell
Developer Express Inc.
Oct 26 '06 #2


"Dustin Campbell" <du*****@no-spam-pleasedevexpress.comwrote in message news:c1**************************@news.microsoft.c om...

Unfortunately, this can't be done (and I don't see how "typeof" is used here).
About the usage of typeof, here is an example of what I mean (this works):

class Program
{
static void Main(string[] args)
{
Test test = new Test();
test.CallMe();
}
}

class Test
{
public void CallMe()
{
this.DoSomething<Test>();
}
public void DoSomething<T>() where T : class, new()
{
Console.WriteLine(typeof(T).FullName);
}
}

Here I can use typeof to get the type of a Type Parameter. I was hoping that there was a way (maybe using typeof) to solve the first problem.
The closest that you could get is to make the StartHere method generic like
this:

class A
{
T DoSomething<T>() where T : class, new()
{
T ThisObj = new T();
// Do something usefull...
return ThisObj;
}

void StartHere<T>()
{
// And here is the problem
T myValue = DoSomething<T>();
}
}
I know, but in my case I am retrieving the type of a property using reflection, and that is the type that I need to pass to the generic DoSomething, so no point to make the initial call generic. The other option is to make a non-generic version of DoSomething and just eat the performance impact of the boxing.

Jorge Varas

Oct 26 '06 #3
You can, but you need to use reflection, which is (relatively) slow; in
particular, you would obtain the MethodInfo for the method ("GetMethod"),
and then call MakeGenericMethod(), which accepts the Type instances.

You would then .Invoke the returned method info.

Marc
Oct 26 '06 #4
I know, but in my case I am retrieving the type of a property using
reflection, and that is the type that I need to pass to the generic
DoSomething, so no point to make the initial call generic. The other
option is to make a non-generic version of DoSomething and just eat
the performance impact of the boxing.
If you're already using reflection, boxing should be the least of your performance
worries. :-) Second of all, the generic constraints that you've applied to
DoSomething<Tensure that their won't be any boxing operations because only
reference types can be used with it. And finally, if you're using reflection,
you *could* use reflection to dynamically set the generic argument to your
method and invoke it like this:

using System;
using System.Reflection;

namespace ConsoleApp
{
class Program
{
class A
{
T DoSomething<T>() where T: class, new()
{
T ThisObj = new T();
// Do something usefull...
return ThisObj;
}

public void StartHere(Type type)
{
MethodInfo method = this.GetType().GetMethod("DoSomething", BindingFlags.NonPublic
| BindingFlags.Instance);
MethodInfo closedMethod = method.MakeGenericMethod(type);

object o = closedMethod.Invoke(this, null);
}
}

static void Main(string[] args)
{
new A().StartHere(typeof(A));
}
}
}

Of course, if the "class" generic constraint isn't used, there would potentially
be boxing because the Invoke() method returns a System.Object.

Best Regards,
Dustin Campbell
Developer Express Inc.
Oct 26 '06 #5
Cool!

I was not aware of MakeGenericMethodt. I'll give it a try.

{ ... things I have to do because C# has a very limited support for AOP }
"Marc Gravell" <ma**********@gmail.comwrote in message
news:Oq****************@TK2MSFTNGP03.phx.gbl...
You can, but you need to use reflection, which is (relatively) slow; in
particular, you would obtain the MethodInfo for the method ("GetMethod"),
and then call MakeGenericMethod(), which accepts the Type instances.

You would then .Invoke the returned method info.

Marc

Oct 26 '06 #6
I am caching the reflection information, but is still in reflected types
format (propertyInfo and so) so my performace is prety good (or my pc is
pretty fast, whichever is working) because I cache the information on
program start up, rather than at every call.

The boxing operation that I was worry about was going to be if I needed to
make a non-generic version (thus object type based) version of the same
function.

As I pointed out to mark, I didn't know about the "MakeGenericMethod" usage,
so I'll give it a try.

"Dustin Campbell" <du*****@no-spam-pleasedevexpress.comwrote in message
news:c1**************************@news.microsoft.c om...
>I know, but in my case I am retrieving the type of a property using
reflection, and that is the type that I need to pass to the generic
DoSomething, so no point to make the initial call generic. The other
option is to make a non-generic version of DoSomething and just eat
the performance impact of the boxing.

If you're already using reflection, boxing should be the least of your
performance worries. :-) Second of all, the generic constraints that
you've applied to DoSomething<Tensure that their won't be any boxing
operations because only reference types can be used with it. And finally,
if you're using reflection, you *could* use reflection to dynamically set
the generic argument to your method and invoke it like this:

using System;
using System.Reflection;

namespace ConsoleApp
{
class Program
{
class A
{
T DoSomething<T>() where T: class, new()
{
T ThisObj = new T();
// Do something usefull...
return ThisObj;
}

public void StartHere(Type type)
{
MethodInfo method = this.GetType().GetMethod("DoSomething",
BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo closedMethod = method.MakeGenericMethod(type);

object o = closedMethod.Invoke(this, null);
}
}

static void Main(string[] args)
{
new A().StartHere(typeof(A));
}
}
}

Of course, if the "class" generic constraint isn't used, there would
potentially be boxing because the Invoke() method returns a System.Object.

Best Regards,
Dustin Campbell
Developer Express Inc.


Oct 26 '06 #7
The boxing operation that I was worry about was going to be if I
needed to make a non-generic version (thus object type based) version
of the same function.
Sure, but I assumed that you weren't going to be using value types since
you had declared the "class" generic constraint. If you have an object-type
parameter but never use a value type with it, you won't have boxing.

Best Regards,
Dustin Campbell
Developer Express Inc.
Oct 26 '06 #8
Then there is something more I need to learn... What I understand from what
you are saying is that there never is boxing between reference types? only
for value types that are used as objects?

Thus this piece of code does not do any boxing on the third line?

StringBuilder sb = new StringBuilder();
sb.Add("Whatever");
object o = (object)sb;
Console.WriteLine(o.ToString());

Jorge Varas

"Dustin Campbell" <du*****@no-spam-pleasedevexpress.comwrote in message
news:c1**************************@news.microsoft.c om...
>The boxing operation that I was worry about was going to be if I
needed to make a non-generic version (thus object type based) version
of the same function.

Sure, but I assumed that you weren't going to be using value types since
you had declared the "class" generic constraint. If you have an
object-type parameter but never use a value type with it, you won't have
boxing.

Best Regards,
Dustin Campbell
Developer Express Inc.


Oct 26 '06 #9
Then there is something more I need to learn... What I understand from
what you are saying is that there never is boxing between reference
types? only for value types that are used as objects?

Thus this piece of code does not do any boxing on the third line?

StringBuilder sb = new StringBuilder();
sb.Add("Whatever");
object o = (object)sb;
Console.WriteLine(o.ToString());
Correct.

This code:

private void Test()
{
StringBuilder sb = new StringBuilder();
sb.Append("Whatever");
object o = (object)sb;
Console.WriteLine(o.ToString());
}

Compiles to this:

..method private hidebysig instance void Test() cil managed
{
.maxstack 2
.locals init (
[0] [mscorlib]System.Text.StringBuilder sb,
[1] object o)
L_0000: nop
L_0001: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()
L_0006: stloc.0
L_0007: ldloc.0
L_0008: ldstr "Whatever"
L_000d: callvirt instance [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
L_0012: pop
L_0013: ldloc.0
L_0014: stloc.1
L_0015: ldloc.1
L_0016: callvirt instance string object::ToString()
L_001b: call void [mscorlib]System.Console::WriteLine(string)
L_0020: nop
L_0021: ret
}

This code:

private void Test()
{
int i = 1;
object o = (object)i;
Console.WriteLine(o.ToString());
}

Compiles to this:

..method private hidebysig instance void Test() cil managed
{
.maxstack 1
.locals init (
[0] int32 i,
[1] object o)
L_0000: nop
L_0001: ldc.i4.1
L_0002: stloc.0
L_0003: ldloc.0
L_0004: box int32
L_0009: stloc.1
L_000a: ldloc.1
L_000b: callvirt instance string object::ToString()
L_0010: call void [mscorlib]System.Console::WriteLine(string)
L_0015: nop
L_0016: ret
}

Notice the boxing operation in the second method when the Int32 is cast to
an object.


Best Regards,
Dustin Campbell
Developer Express Inc.

Oct 26 '06 #10
Thanks for the explanation and your time.

One of these days I need to learn CLI, Emit() and all that area of .Net.
(Can you suggest a good starting point?)

All the hoops and loops that I am doing is to be able to intercept access to
properties of a class. I know that this can be done by inhert the class from
ContextBound and intercepting the call sink. But .Net supports only single
inheritance, which prevents me from using inheritance in my business model
if I also have to inherit from ContextBound.

I know about this project:

http://wwwse.fhs-hagenberg.ac.at/se/...h/aop_net.html

But I have not see a single example of it. Do you know more references?

Jorge Varas

"Dustin Campbell" <du*****@no-spam-pleasedevexpress.comwrote in message
news:c1**************************@news.microsoft.c om...
>Then there is something more I need to learn... What I understand from
what you are saying is that there never is boxing between reference
types? only for value types that are used as objects?

Thus this piece of code does not do any boxing on the third line?

StringBuilder sb = new StringBuilder();
sb.Add("Whatever");
object o = (object)sb;
Console.WriteLine(o.ToString());

Correct.

This code:

private void Test()
{
StringBuilder sb = new StringBuilder();
sb.Append("Whatever");
object o = (object)sb;
Console.WriteLine(o.ToString());
}

Compiles to this:

.method private hidebysig instance void Test() cil managed
{
.maxstack 2
.locals init (
[0] [mscorlib]System.Text.StringBuilder sb,
[1] object o)
L_0000: nop L_0001: newobj instance void
[mscorlib]System.Text.StringBuilder::.ctor()
L_0006: stloc.0 L_0007: ldloc.0 L_0008: ldstr "Whatever"
L_000d: callvirt instance [mscorlib]System.Text.StringBuilder
[mscorlib]System.Text.StringBuilder::Append(string)
L_0012: pop L_0013: ldloc.0 L_0014: stloc.1 L_0015: ldloc.1 L_0016:
callvirt instance string object::ToString()
L_001b: call void [mscorlib]System.Console::WriteLine(string)
L_0020: nop L_0021: ret }

This code:

private void Test()
{
int i = 1;
object o = (object)i;
Console.WriteLine(o.ToString());
}

Compiles to this:

.method private hidebysig instance void Test() cil managed
{
.maxstack 1
.locals init (
[0] int32 i,
[1] object o)
L_0000: nop L_0001: ldc.i4.1 L_0002: stloc.0 L_0003: ldloc.0 L_0004:
box int32
L_0009: stloc.1 L_000a: ldloc.1 L_000b: callvirt instance string
object::ToString()
L_0010: call void [mscorlib]System.Console::WriteLine(string)
L_0015: nop L_0016: ret }

Notice the boxing operation in the second method when the Int32 is cast to
an object.


Best Regards,
Dustin Campbell
Developer Express Inc.

Oct 26 '06 #11
It isn't just obtaining the PropertyInfo, MethodInfo (etc) instances that is
slow; it is also (comparatively) slow when *using* them - e.g. GetValue /
SetValue for properties, Invoke for members... all slower, as it has to do a
lot to enusure you aren't attempting bad things. Quite painful if you are in
a tight loop.

Sometimes reflection is necessary; but in a lot of cases it is [ab]used
because it gets the programmer out of a hole. Often, suitable interface
declarations can be used to make this a *lot* quicker. Alternatively,
(typed) delegates can sometimes be suitable (especially in 2.0 where they
are quicker).

I don't know enough about your other code to know if it is being used wisely
(not do I really want to know ;-p) - I'm just making a generalisation.
Saying that; if you're code works, it may be inadvisable to hack it too
much... but worth considering for the future.

Marc
Oct 26 '06 #12
I am not in such tight loop. It is not a high performance app where every
milli-second count. So reflection performance is ok.
I am tinkering with my own code, not someone elses, so I can hack it as much
as I want. I don;t want to tie to specific interfaces or inherit from
certain class. I just want to decorate with attributes and the code being
intercepted, but looks like there is no way out of using reflection, or
inherit from ContextBoundObject.

The only project that did something in this style was:
http://wwwse.fhs-hagenberg.ac.at/se/...h/aop_net.html

But the guy will not give a sample.

Is there any recomended place to start studing the Emit codes and the
CLI/CLR?

Jorge Varas
"Marc Gravell" <ma**********@gmail.comwrote in message
news:ub****************@TK2MSFTNGP05.phx.gbl...
It isn't just obtaining the PropertyInfo, MethodInfo (etc) instances that
is slow; it is also (comparatively) slow when *using* them - e.g. GetValue
/ SetValue for properties, Invoke for members... all slower, as it has to
do a lot to enusure you aren't attempting bad things. Quite painful if you
are in a tight loop.

Sometimes reflection is necessary; but in a lot of cases it is [ab]used
because it gets the programmer out of a hole. Often, suitable interface
declarations can be used to make this a *lot* quicker. Alternatively,
(typed) delegates can sometimes be suitable (especially in 2.0 where they
are quicker).

I don't know enough about your other code to know if it is being used
wisely (not do I really want to know ;-p) - I'm just making a
generalisation.
Saying that; if you're code works, it may be inadvisable to hack it too
much... but worth considering for the future.

Marc

Oct 26 '06 #13

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

27 posts views Thread by Bernardo Heynemann | last post: by
23 posts views Thread by Luc Vaillant | last post: by
9 posts views Thread by sloan | last post: by
1 post views Thread by Vladimir Shiryaev | last post: by
11 posts views Thread by Einar Værnes | last post: by
2 posts views Thread by =?Utf-8?B?SmVzcGVyLCBEZW5tYXJr?= | last post: by
13 posts views Thread by rkausch | last post: by
3 posts views Thread by Stefan Hoffmann | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.