Reputation: 10536
I want to convert a C# style generic type string, like:
"System.Dictionary<System.String, System.String>"
To its CLR equivalent:
"System.Dictionary`1[System.String, System.String]"
and back. Is there an easy way to do this, or do I have to resort to string manipulation?
EDIT:
I only have the string representation in C#/VB/etc style form. I don't have a Type object or something similar at hand. An alternate question would have been: how to get a Type object from a string representation like "System.Dictionary<System.String, System.String>"
(after that I can get the full name of the type object).
EDIT#2:
Justification: I'm creating objects dynamically using CodeDom
. The input from which I'm generating the CodeDom
might contain types in C#
(or any other proprietary like VB.NET) format, but I have to use them inside a CodeTypeReference
, which only accepts the CLR style format.
Upvotes: 3
Views: 2141
Reputation: 36
I believe I faced a similar issue in the past and wrote the following utility method to address it :
// Utilitiy to convert class name string to namespace-qualified name
public static Type GetTypeByName(string ClassName,
string TypesNamespacePrefix = "AssemblyTopLevel.AssemblyMidLevel.",
Dictionary<string, Type> ConcreteTypeMap = null)
{
if ((ConcreteTypeMap != null) && (ConcreteTypeMap.ContainsKey(ClassName)))
return ConcreteTypeMap[ClassName];
if ((ConcreteTypeMap != null) && (ConcreteTypeMap.ContainsKey(TypesNamespacePrefix + ClassName)))
return ConcreteTypeMap[TypesNamespacePrefix + ClassName];
try
{
if (Type.GetType(ClassName) != null)
return Type.GetType(ClassName);
}
catch { }
try
{
if (Type.GetType(TypesNamespacePrefix + ClassName) != null)
return Type.GetType(TypesNamespacePrefix + ClassName);
}
catch { }
Stack<int> GenericCounterStack = new Stack<int>();
Stack<int> GenericStartIndexStack = new Stack<int>();
Dictionary<int, int> GenericCountMapByStartIndex = new Dictionary<int, int>();
int Count = 1;
int GenericStartIndex = -1;
int PreviousHighestGenericIndex = -1;
foreach (char c in ClassName)
{
if (c.Equals('<'))
{
if (GenericStartIndex != -1)
{
GenericCounterStack.Push(Count);
GenericStartIndexStack.Push(GenericStartIndex);
}
Count = 1;
GenericStartIndex = PreviousHighestGenericIndex + 1;
PreviousHighestGenericIndex = Math.Max(GenericStartIndex, PreviousHighestGenericIndex);
}
else if (c.Equals(','))
{
Count++;
}
else if (c.Equals('>'))
{
GenericCountMapByStartIndex[GenericStartIndex] = Count;
if (GenericCounterStack.Count != 0)
Count = GenericCounterStack.Pop();
if (GenericStartIndexStack.Count != 0)
GenericStartIndex = GenericStartIndexStack.Pop();
}
}
ClassName = ClassName.Replace("<" + TypesNamespacePrefix, "<");
StringBuilder FullyQualifiedClassName = new StringBuilder(TypesNamespacePrefix);
GenericStartIndex = 0;
foreach (char c in ClassName)
{
if (c.Equals('<'))
{
FullyQualifiedClassName.Append("`" + GenericCountMapByStartIndex[GenericStartIndex].ToString()
+ "[" + TypesNamespacePrefix);
GenericStartIndex++;
}
else if (c.Equals(','))
{
FullyQualifiedClassName.Append("," + TypesNamespacePrefix);
}
else if (c.Equals('>'))
{
FullyQualifiedClassName.Append("]");
}
else
FullyQualifiedClassName.Append(c);
}
ClassName = FullyQualifiedClassName.ToString();
return Type.GetType(ClassName);
}
You may optionally provide a concrete type map, to optimize for commonly-invoked cases:
static readonly Dictionary <string, Type> MyConcreteTypeMap = new Dictionary<string,Type>()
{
{"SomeClass", typeof(SomeClass)},
{"AnotherClass", typeof(AnotherClass)}
}
So, the invocation looks like this:
Type DesiredType = GetTypeByName("SomeClass", "", MyConcreteTypeMap);
or
Type DesiredType = GetTypeByName("SomeOtherClass", "MyAssemblyTopLevel.MyAssemblyMidLevel.");
or
Type DesiredType = GetTypeByName("SomeOtherClass");
or, quite usefully,
Type DesiredType = GetTypeByName("SomeOtherClass<OuterTemplate<InnerTemplate1,InnerTemplate2<InnerInnerTemplate1>>>");
or, for the original example,
Type DesiredType = GetTypeByName("Dictionary<String,String>", "System.");
Upvotes: 2
Reputation: 55184
For the .NET to C# direction, I can't see an easy way to do it; you may have to actually parse the type yourself.
In the other direction, it's pretty easy:
public static string DotNetToCSharp(string tyName) {
var provider = new Microsoft.CSharp.CSharpCodeProvider();
return provider.GetTypeOutput(new System.CodeDom.CodeTypeReference(tyName));
}
Upvotes: 4
Reputation: 76500
typeof(System.Dictionary<System.String, System.String>).FullName
should get you something like:
System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Might need to do some replacement on the full type names inside the type parameter spec. However if you use the below code
typeof(Dictionary<System.String, System.String>).ToString()
You will get something like this:
System.Collections.Generic.Dictionary`2[System.String,System.String]
To convert back into a Type
use
Type.GetType("System.Collections.Generic.Dictionary`2[System.String,System.String]");
EDIT I've tried hacking this with dynamic expressions but didn't have much luck. I think, other than parsing the string, you can use a "nuclear option" and compile a DLL using CSharpCodeProvider
and then load it using Assembly.LoadFile
and execute a method that will evaluate typeof(...).
Upvotes: 0
Reputation: 22443
I think this is what you were looking for...
var dict = new Dictionary<string, string>();
var type = dict.GetType();
var typeName = type.FullName;
var newType = Type.GetType(typeName);
Console.WriteLine(type == newType); //true
Upvotes: 0
Reputation: 18286
I am not sure I completely understand your question.
Anyway -when you instantiate a genetic class Class<T1, ... ,Tn>
the defined in namespace Namespace, for example
Namespace.Class<T1, ... ,Tn> a = new Namespace.Class<Type1,...,Typen>();
a.GetType().FullName will give you the full string representation of the class
which will be "Namespace.Class'n<Type1,...,Typen>"
Upvotes: 0
Reputation: 55946
typeof(System.Dictionary<System.String>, System.String>).FullName
As for the reverse, no clue :(
Upvotes: 0