2

I know that I can obtain a type from string name like so

Type intType = Type.GetType("System.Int32");

But, what if I have string like so

string[] typeNameArr = new string[] {"Int", "String", "DateTime", "Bool"};

How to convert these to actual types? Maybe I can get full qualified name out of an alias and then do the GetType?

Stefan
  • 17,448
  • 11
  • 60
  • 79
Talha
  • 107
  • 9
  • You could add your own `if` conditions to always evaluate "Int" as "System.Int32". – Standard_101 May 26 '21 at 10:08
  • 3
    Your array of strings is odd. `Int` needs to become either `int` or `System.Int32`, whereas `DateTime` needs to become `System.DateTime` (there's no DateTime language alias). I think you're going to have to special-case some of these -- have a look-up which knows about `Int` etc, and just try prepending `System.` to those which aren't in your lookup – canton7 May 26 '21 at 10:09
  • @canton7 I know. But even if its "int" can I convert it to typeof(int) dynamically without using a hard coded if else? – Talha May 26 '21 at 10:12
  • 3
    Sounds like you basically want a `Dictionary` - add every type you know about from the web service to that dictionary. – Jon Skeet May 26 '21 at 10:12
  • @Talha Even if you can convert it to `int`, you'll need to manually map that to `System.Int32` in order to use it with `Type.GetType` – canton7 May 26 '21 at 10:13
  • @JonSkeet I thought of that. But I was wondering if I can do it dynamically via reflection or so. Predefined dictionary would be my last option. – Talha May 26 '21 at 10:14
  • 2
    Also, instantiating arbitrary types based on deserialized data is a **huge security hole**. There are types hiding away in the BCL which will do arbitrary things when they're instantiated, and attackers can use this to perform remote code execution. You **must** white-list any sort of object creation to just known-safe types – canton7 May 26 '21 at 10:14
  • @canton7 Don't we have anything where we can get a type by using alias string only? – Talha May 26 '21 at 10:15
  • 1
    No. The alias is a C# language concept, but `Type.GetType` is provided by the runtime and is used for all CLR languages – canton7 May 26 '21 at 10:16
  • 2
    Do you actually have that much variation in the type? Just writing the dictionary is faster than fiddling with reflection. – Martheen May 26 '21 at 10:16

2 Answers2

6

If you use fully qualified names, like "System.Int32" in the end you'll be able to to it through linq:

var types = typeNameArr.Select(c => Type.GetType(c));

Additionally: if your web-service provide custom names, you either need a mapping or a convention. E.g.:

var types = typeNameArr.Select(c => Type.GetType("System." + c));

or

var types = typeNameArr.Select(c => 
{
   switch (c)
   {
      "Int":
          return typeof(int);
      "Foo":
          return typeof(BarClass);  
      default:
          return  null
   }        
});
Stefan
  • 17,448
  • 11
  • 60
  • 79
  • I am getting this array from a WebService so I cannot use fully qualified names here. I need a dynamic way of correctly converting these to actual c# types. – Talha May 26 '21 at 10:09
  • 1
    @Talha: But `Int` is neither a .NET Type (that would be `System.Int32`) nor a C# alias (that would be `int` with a lowercase `i`)! Thus, I'm afraid you'll have to hard-code a conversion table yourself (for example, with a large switch statement). – Heinzi May 26 '21 at 10:10
  • @Heinzi I know. But that I can change to lowercase. – Talha May 26 '21 at 10:11
  • 3
    @Talha: Since the [list of C# aliases](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types) fairly short and unlikely to change, I would definitely argue for a large, hard-coded `switch` statement rather than using some framework magic. – Heinzi May 26 '21 at 10:13
  • 2
    You might as well do a mapping from `string` to `Type` at this point: `c switch { "Int" => typeof(int), ... }` – canton7 May 26 '21 at 10:21
3

To get all primitive types with their alias you can write:

string assemblyFullName = "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
var assembly = Assembly.Load(assemblyFullName);
var primitiveTypes =
    assembly.DefinedTypes.Where(definedType => definedType.IsPrimitive && definedType != typeof(IntPtr) && definedType != typeof(UIntPtr));

using (var provider = new CSharpCodeProvider())
{
    var result = primitiveTypes.Select(x => (Alias: provider.GetTypeOutput(new CodeTypeReference(x)), Type: x));
}

Would result in:

bool    typeof(Boolean)
byte    typeof(Byte)
char    typeof(Char)
double  typeof(Double)
short   typeof(Int16)
int     typeof(Int32)
long    typeof(Int64)
sbyte   typeof(SByte)
float   typeof(Single)
ushort  typeof(UInt16)
uint    typeof(UInt32)
ulong   typeof(UInt64)
Magnus
  • 45,362
  • 8
  • 80
  • 118
  • What to do with `DateTime`? Why the answer and not just a comment with reference to [this](https://stackoverflow.com/q/59005990/1997232) or [this](https://stackoverflow.com/q/2442534/1997232)? – Sinatr May 26 '21 at 11:19
  • Just add a manual mapping for it. Adding a manual mapping for all the types might very well be the best solution, just wanted to show that it could also be done using code. – Magnus May 26 '21 at 17:48