Omer_Mor

I need to find a way to get the type of a containing class, without explicitly using it's name, and doing it statically.

In the past I used to do something like this:
Code Block
static Type s_myType = MethodBase.GetCurrentMethod().DeclaringType;

However, this approach does not work well for generic types since it returns the type of the open generic type, and the closed one. What i mean is that for the closed type MyClass, I will not get the type of MyClass but the open type MyClass<>.

I know I can explicitly write typeof(MyClass) but I want to do this without explicitly stating the name of the class.
I know visual studio does that when it displays the call stack: it shows all the closed generic types in their corresponding frames. However I suspect it does that through the debugging interfaces, and not using the reflection methods available to us developers.
Thanks,



Re: .NET Base Class Library Statically obtaining the type of the containing class

nobugz

This info is in fact available from reflection, you'll just have to make it look pretty like the debugger does. Try something like this:

public class MyClass<T> {
public void DumpName() {
Console.WriteLine(TypeName(this.GetType()));
}
public static string TypeName(Type t) {
string name = t.Name;
if (t.IsGenericType) {
int ix = name.IndexOf('`');
if (ix >= 0) name = name.Remove(ix);
Type[] args = t.GetGenericArguments();
name += "<";
for (ix = 0; ix < args.Length; ++ix) {
if (ix > 0) name += ", ";
name += TypeName(args[ix]);
}
name += ">";
}
return name;
}
}

With this test code:
new MyClass<int>().DumpName();
new MyClass<string>().DumpName();
new MyClass<Dictionary<string, int>>().DumpName();

You'll see this output:
MyClass<Int32>
MyClass<String>
MyClass<Dictionary<String, Int32>>





Re: .NET Base Class Library Statically obtaining the type of the containing class

Omer_Mor

Thanks for your help, but this would work only when you have an instance of the class ("this"). I specifically said statically obtaining the type, where you can't use this.GetType() because there's no this.






Re: .NET Base Class Library Statically obtaining the type of the containing class

nobugz

Umm, wasn't your question about making it look pretty You hinted that you, somehow, already knew how to obtain the Type instance.





Re: .NET Base Class Library Statically obtaining the type of the containing class

Omer_Mor

On the contrary - obtaining the type is my problem (as mentioned in the subject of the thread).

As I said - I know how to get the type of the open generic type, but not the closed generic type. At least not statically.

I can of course explicitly write the name of the class (typeof(MyClass<T>)), but I need to find another way, with no hard coding the name of the class.






Re: .NET Base Class Library Statically obtaining the type of the containing class

MatteoSp

Interesting question, it tooks more than an hour to me. And still I feel as I'm missing something about generics type represntation at compile time and at run time. By the way, look at this:


Code Block

Type openType = MethodBase.GetCurrentMethod().DeclaringType;
Type closedType = openType.MakeGenericType(typeof(T));

Debug.Assert(openType.ContainsGenericParameters);
Debug.Assert(!closedType.ContainsGenericParameters);


m.





Re: .NET Base Class Library Statically obtaining the type of the containing class

nobugz

What's wrong with this.GetType()





Re: .NET Base Class Library Statically obtaining the type of the containing class

MatteoSp

nobugz wrote:
What's wrong with this.GetType()


Do you read before answering





Re: .NET Base Class Library Statically obtaining the type of the containing class

nobugz

I usually do. Today is my off-day.





Re: .NET Base Class Library Statically obtaining the type of the containing class

Omer_Mor

nobugz: You can't use this.GetType() because there's no "this" instance in a static context. I already mentioned it in my previous reply.

MatteoSp: Thanks for trying, but your solution is still not good enough: You explicitly used the name of the type parameter ("typeof(T)"). I need a general way with no explicit type names to get the type. Maybe it's just not possible. I still wonder how visual studio does that in their Call Stack window. Maybe I'll ask in the debugging forum.






Re: .NET Base Class Library Statically obtaining the type of the containing class

MatteoSp

Before posting my solution I thught this one would have worked:

Code Block

Type openType = MethodBase.GetCurrentMethod().DeclaringType;
Type[] typesParamters = openType.GetGenericArguments();
Type closedType = openType.MakeGenericType(typesParamters);

Debug.Assert(openType.ContainsGenericParameters);
Debug.Assert(!closedType.ContainsGenericParameters);


But it does not work, the second assertion fails. Why you need a more general solution You are in a static context, so your routine cannot be inherited. You have to write that static method in every class, don't you

I add a couple of thoughts:

1) About Visual Studio: I don't think it have the constraint to work in a static context, it does it's inspections on instances, not on types. What you think

2) About the debugging capabilities: this solution is not a general one: it would work only when debugging symbols are available.What about a release-complied code

m.






Re: .NET Base Class Library Statically obtaining the type of the containing class

Mike Stall - MSFT

Visual Studio and debuggers do indeed use a special debugging API (ICorDebug) to examine callstacks and deal with this, they don't use reflection. (http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=2254267&SiteID=1)

I think MatteoSp has it.

I think you'll need a specific reference to typeof(T). If nothing else, you'll want the reference to T to ensure ensure that the optimizing doesn't do code-folding on you across compatible generic types.

That seems reasonable because when you refer to s_myType, you're from a static context and need to have T available anyways.






Re: .NET Base Class Library Statically obtaining the type of the containing class

Omer_Mor

As for the why I need it:

I wanted a short code snippet (actually a ReSharper template, but it's practically the same) that would get me the type. The snippet can't use the type name because it's not dynamic. I need the type as input for log4net's Logger constructor, and I need the Logger instance to be available also in a a static context.

The snippet is actually something like this:

Code Block
static ILog s_log = new Logger( < enter code to get type here > );

1) About vs: it can't do it's inspections on instances because some of the frames in the call stack are from static methods.

2) I did not understand why symbols would be needed

Mike: Thanks for participating. However, if indeed the only way is through explicitly writing the names of the type parameters, I'll have to find other solutions. It seems though like reflections should have been be able to do this, like it does for non generic types.






Re: .NET Base Class Library Statically obtaining the type of the containing class

Rick Byers - MSFT

Hi,

This is a known limitation of GetCurrentMethod (the StackTrace class also has this limitation) - eg. see http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx FeedbackID=267378. VS appearing able to do this is misleading you - it isn't guarenteed to work all the time. The debugging implementation makes a best effort to recover the full generic info but JIT optimizations can defeat it. To see this, try debugging your code with JIT optimizations disabled (build in Release mode, disable the "suppress JIT optimizations" and "enable Just-my-code" options in VS) and look at the callstack in VS when in a static method instantiated at a reference type. Instead of seeing, for example, "G<string>.Foo()" in the call stack, you'll see "G<System.__Cannon>.Foo()". The debugger can tell this is the instance of Foo that expects T to be a reference type, but (since the code is the same), it can't tell which reference type exactly.

This doesn't mean the information can't otherwise be made available - the fact that typeof(T) works in that case implies there can still be some way to get the type. What's happening here is that by using a statement like typeof(T) in the method, it effectively indicates to the CLR that the optimization must be disabled - that full information will be needed. This is somewhat of a special case, and neither reflection nor the debugger support actually finding the information in that case.

In theory it would be possible to add support for this - in fact we debated it internallynear the end of V2.0. Unfortunately it would be a fairly significant change - all the JIT compilers would have to know to treat GetCurrentMethod as special to ensure the needed generic instantiation information was always available. By the time we discussed this, it was too late to make a change of this magnitude before the 2.0 release, and using typeof(T) has been considered a good-enough work-around.

Let me know if you think it would be worth it to add this in a future version of the CLR (knowing that it is a fair amount of work that would take away from other possible features). I obviously can't promise anything, but it helps to know how our customers would prioritize the work we could do in future versions.

I hope this helps,

Rick





Re: .NET Base Class Library Statically obtaining the type of the containing class

Omer_Mor

Rick,

Thank you very much for the detailed explanation. It is a very interesting read.

Although it's a pity one can't obtain the type of the closed generic container class without resorting to explicit type names, it is also not such a bug deal (at least not for me).

It's also good to know that using typeof(T) will have performance issues due to the disabled optimiziation. I'll keep that in mind.