Click here to Skip to main content
15,884,237 members
Please Sign up or sign in to vote.
5.00/5 (3 votes)
See more:
Sounds like a stupid question, but here's the problem.

I have, say:

IEnumerable<DataRow> t;

obviously, typeof(t).FullName will give me:

System.Collections.Generic.IEnumerable`1[[System.Data.DataRow, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

But that's not what I want. I want "IEnumerable<DataRow>" so I can use this in some runtime generated code.

Can't find anything to convert a type back to its "type" as represented by a string, not the FullName. Maybe I'm just blind.

Marc
Posted

A rough and ready method (knocked together in a couple of minutes) would be to do this:
C#
public class TypeResolver
{
  public string EvaluateType(Type type)
  {
    StringBuilder retType = new StringBuilder();

    if (type.IsGenericType)
    {
      string[] parentType = type.FullName.Split('`');
      // We will build the type here.
      Type[] arguments = type.GetGenericArguments();

      StringBuilder argList = new StringBuilder();
      foreach (Type t in arguments)
      {
        // Let's make sure we get the argument list.
        string arg = EvaluateType(t);
        if (argList.Length > 0)
        {
          argList.AppendFormat(", {0}", arg);
        }
        else
        {
          argList.Append(arg);
        }
      }

      if (argList.Length > 0)
      {
        retType.AppendFormat("{0}<{1}>", parentType[0], argList.ToString());
      }
    }
    else
    {
      return type.ToString();
    }

    return retType.ToString();
  }
}
There are very probably huge gaping holes in it, but this should be enough to get started. It quite happily converted types like this:
C#
EvaluateType(typeof(Dictionary<string, List<Dictionary<int, bool>>>));
 
Share this answer
 
Everything is correct. This is the name of the type, which is not the same as the declared name you would use in your generated code.

(By the way, to start with, do you know the difference between run-time and compile-time types? If you instantiated t, your could call t.GetType().FullName, but that would never be a the type IEnumerable<DataRow> because the interface is an abstract class, so a run-time type could be only some class (or structure!) implementing IEnumerable<DataRow>. That was just a side note.)

Now, do you really need to reproduce a text of declaration of IEnumerable<DataRow>? You should do something very different.

You need to use Reflection. You get a meta-model of your type using either typeof (compile-time type) or GetType() (run-time type which does not exist for interfaces). This operator or call will both return you an object of the type System.Type. This is where Reflection starts.

Please see:
http://msdn.microsoft.com/en-us/library/system.type.aspx[^].

Using System.Type methods and properties, you can find out if your type contains generic parameters using ContainsGenericParameters. You can get generic arguments using GetGenericArguments and their names. In brief, learn all the members of System.Type containing "Generic" and other relevant members and learn how to generate code using then. By the way, it may be hard to understand from the first glance, but quite easy to research and develop the code, especially using the debugger.

Good luck,
—SA
 
Share this answer
 
List<t> is pretty much a strongly typed array with a bunch of really handy extra functionality. IEnumerable<t> isn't an array, but rather a non-indexed collection of objects that can be enumerated (meaning looped through). IEnumerable<t> is the most basic interface that must be implemented by an object for it to support foreach.

If the method signature says IEnumerable, then that's what it is returning. List<T> can be implicitly cast to IEnumerable<T>, but you'll have to explicitly cast to go from IEnumerable<T> to List<T>:

C#
IEnumerable<String> ienum = new List<String>();
List<String> list = (List<String>)ienum;
 
Share this answer
 
Comments
Marc Clifton 28-Feb-12 21:44pm    
I know what you're getting at, but I need to actual type for a dynamic, runtime piece of code which, among other things, replaces a token with the generic type used to construct the code generator. So, if, for example, I instantiate the code generator like this:

new Foo<SomeType>()

Then, part of the code generation process replaces the token /SourceType/ source; with SomeType source;

By the way, the code generator in question is LinqTextQueryRuntime, a CodePlex project. Yes, there's better ways, with expression trees, but I'm just dabbling with different options for dynamic runtime LINQ.

Marc
Sergey Alexandrovich Kryukov 28-Feb-12 22:10pm    
Marc, this answer is not it.

I think I understand what you need. This is a pretty simple Reflection problem. I tried to give you the idea in my answer. I think you can pretty easily find out the solution. If you get stuck, ask a follow-up question; I'll gladly help you. I might need some 20-30 minutes of my work to get all the detail. If you need help like that, please try to formulate in more general case what on input and what's on output.

--SA
Marc Clifton 29-Feb-12 7:22am    
No, you're totally missing the point. I need to PARSE the type's FullName, a very crude example:

<pre>

public string ConvertToTypeAsString(string t)
{
string ret = t;

if (t.Contains("`"))
{
// System.Collections.Generic.IEnumerable`1[[System.Data.DataRow, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
t = t.RightOf('.').RightOf('.').RightOf('.');
// IEnumerable`1[[System.Data.DataRow, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
ret = t.LeftOf('`') + "<";
// IEnumerable<
t = t.RightOfRightmost('[').LeftOf(',').RightOfRightmost('.');
// System.Data.DataRow, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
// System.Data.DataRow
// DataRow
ret += t + ">";
// IEnumerable<datarow>
}

return ret;
}
</pre>

Marc
Sergey Alexandrovich Kryukov 29-Feb-12 15:27pm    
Marc,

I don't think I'm missing it. Please pay attention: you never mentioned parsing any text before. You only mentioned code generation, which is very different thing.

I also suspect that parsing of the type name defeats the purpose no matter what is that purpose.

You can always parse the string the way you show in the code above. But would the result of the parsing be reliable? This text format can be changed in future as the platform gets upgraded. The purpose of the type name is different: the main goal is unique identification of the type. For example, this string is good enough to be a key of the dictionary of something related to the types (not types, because System.Type itself can perfectly be used as a key of the dictionary).

The code generating the unique name of the type does not take enough responsibility to guarantee that the full semantic of the string can be extracted from the string. The only part of data fully responsible for the type structure is concentrated in the meta-data which is fully referenced by the System.Type. And nowhere else, otherwise the principle Don't-Repeat-Yourself would be violated.

Can you understand now, why I explain how to extract information via Reflection, no any other way?

You should also understand, that string representation of some structured data as a single string increase the entropy of the data. This transform is generally irreverseable.

If you are trying to go from code to meta-data through string, you abuse the code consistency. If you have the situation of the pure code text on input -- you will never have the string you mention in your question.

We can really continue this discussion if you explain the ultimate goal of this activity. You explanation of the parsing is not informative enough. So, why? But please explain it in full, otherwise the discussion makes no sense.

Thank you,
--SA
Member 13215913 22-May-17 11:49am    
hi

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900