tags:

views:

84

answers:

4

I have a string such as "Int", "Double", "DateTime" etc. How do I get the fully qualified name from this string?

+2  A: 

Before I go any further, I'd like to point that there is no class in the .NET Framework base class library named Int. There is System.Int32, that in C# happens to have an alias: int.

You can do this several ways.

A simple but limited way to do this is to have a dictionary mapping strings to the corresponding FQNs:

public static IDictionary<string, string> FqnMap = new Dictionary<string, string>
{
    { "Int", "System.Int32" },
    { "Double", "System.Double" },
    { "DateTime", "System.DateTime" },
};

public string GetFqn(string name)
{
    return FqnMap[name]; // TODO: add error handling
}

A more complex but powerful way would involve using reflection to search all types from a set of assemblies. Something like this:

public class FqnResolver
{
    public FqnResolver(IEnumerable<Assembly> assemblies)
    {
        Assemblies = new List<Assembly>(assemblies);
    }
    public FqnResolver(params Assembly[] assemblies) : this(assemblies as IEnumerable<Assembly>) { }
    public FqnResolver() : this(new Assembly[0]) { }

    public ICollection<Assembly> Assemblies { get; private set; }

    public string GetFqn(string name)
    {
        var candidates = from a in Assemblies
                         from t in a.GetTypes()
                         where t.Name == name
                         select t.FullName;
        return candidates.First(); // will throw if no valid type was found
                                   // and does not count duplicates
    }
}
Martinho Fernandes
You don't need the cast to IEnumerable<Assembly> in your second ctor.
dfowler
@dfowler: Apparently I do. A quick check on LinqPad yields: "Constructor 'UserQuery.FqnResolver.FqnResolver(params System.Reflection.Assembly[])' cannot call itself". I really need the cast to force the compiler to pick the first ctor, instead of what would be a recursive constructor call. Also, I think the compiler won't emit any cast and simply call the other ctor directly, but I'll have to confirm that.
Martinho Fernandes
+3  A: 

It's worth bearing in mind that int isn't a type. It's an alias provided by C# for the type System.Int32. Bearing that in mind, and assuming you only care about core types, you can try:

var typeName = "DateTime";

var systemTypesAssembly = Assembly.Load("mscorlib");

var type = (from t in systemTypesAssembly.GetTypes()
           where t.Name == typeName
           select t).FirstOrDefault();

Console.WriteLine(type.FullName);

As I said, this will not work for Int, but would work for Int32 which is the type it's aliased to. This code also contains no error handling for where, for example, no type is found in mscorlib that matches the one you've entered in typeName

Rob
When you're not checking for null-ness of `type`, it's usually better to use `.First()`, since it throws a meaningful exception right away, instead of a meaningless `NullReferenceException` later on.
Martinho Fernandes
Thanks, I was aware that int is definitely not a type, but I can map the string that I get to Int32. Since for now I need only the built-in types, I can use your approach.
@Martinho, in this instance I know exactly what(/why) the null is, but fair point =)
Rob
@user114385, glad I could help! Hopefully that means this is on its way to being the accepted answer? ;=)
Rob
@userrandomnumber: If you also want to support the C# shorthand, just add a dictionary that maps the shorthand to the full type names to this code. The complete list of shorthand type names should be available in MSDN.
Matti Virkkunen
A: 

This is not really doable in an efficient fashion in .Net. In order to get a fully qualified name of a type you will need to have the Type object handy. And in order to get a Type object you typically need an instance, the fully qualified name, or you have to do a bit of searching.

The latter works but is not very efficient as you need to search through every assembly and type in the loaded AppDomain to find the correct answer.

foreach ( var assembly in AppDommain.CurrentDomain.GetAssemblies() ) {
  foreach ( var type in assembly.GetTypes() ) {
    if ( type.Name == target ) {
      return type.FullName;
    }
  }
}

This solution still won't 100% work for you though. Primarily because there is no type "Int" in the .Net framework. It's actual type name is "Int32".

JaredPar
A: 

A type name like "String" can be ambiguous since it could refer to System.String or FooAssembly.String, so you have to search through all types in all loaded assemblies, which could yield multiple results. This bit of reflection could be slow, but you could do the obvious optimization of caching the results at the expense of memory:

static void Main(string[] args)
{
    string typeName = "String";
    foreach (var type in GetFullType(typeName))
    {
        Console.WriteLine(type.FullName);
    }
}

static IEnumerable<Type> GetFullType(string className)
{
    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        foreach (var type in assembly.GetTypes())
        {
            if (type.Name.Equals(className, StringComparison.OrdinalIgnoreCase))
            {
                yield return type;
            }
        }
    }
}
Chris Schmich