0

I'm mapping what will soon be about 30-40 different blocks coming from a CMS by way of JSON which indeed comes with the alias of the block type. Is there a way I can use the alias thats coming through as a string to then directly select the C# type/model in my code?

Currently I'm matching them up like this.

switch (block.Type)
{
  case "Heading":
    mapped = _umbracoMapper.Map<Heading>(block);
    break;
  case "Carousel":
    mapped = _umbracoMapper.Map<Carousel>(block);
    break;
  case "Alert":
    mapped = _umbracoMapper.Map<Alert>(block);
    break;
  case "Text":
    mapped = _umbracoMapper.Map<Text>(block);
    break;
  default:
  break;
}

I understand that the Type isn't really words/letters but is there any way I can reference type to tidy up this repetition, something like..

mapped = _umbracoMapper.Map<[block.Type]>(block);

I'm not 100% sure the above is possible in C#, but I attempted a few versions of the following but its returning System.Type as opposed to (in this case) Blocks.Models.Heading as the mappers Map method requires it to have the target type to be passed to it so it can decipher from which and to what it needs to map. I cant pass it object, dynamic or System.Type, it needs to be the exact type (Heading, Carousel, Alert, Text etc.)

_umbracoMapper.Map(block, Type.GetType("Blocks.Models." + block.Type + ", Blocks"));

Any help would be appreciated!

WNTR
  • 9
  • 2
  • 2
    You seem to be looking for https://stackoverflow.com/questions/232535/how-do-i-use-reflection-to-call-a-generic-method – Rand Random Jul 11 '23 at 07:35
  • Why do you append ", Blocks" the the `GetType()` call? Without this, it should work. Reflection is possible too, but can be slow and is not type safe, so I'd avoid it when working with external data. – PMF Jul 11 '23 at 07:38
  • Have you thought about Hash tables or maybe a dictionary?, i mean you can perform this calculation once and after that just accessing by the `string`? content – DonMiguelSanchez Jul 11 '23 at 07:46
  • @PMF This solution has multiple projects, and although indeed this file is in the **Blocks** project, without that being appended the Type returns back as null. – WNTR Jul 11 '23 at 10:30

1 Answers1

1

You are almost on the correct side. You can use reflection to dynamically create a generic method based on the string value of the block type.

Type type = Type.GetType("Blocks.Models." + block.Type + ", Blocks");
MethodInfo method = typeof(UmbracoMapper).GetMethod("Map");
MethodInfo generic = method.MakeGenericMethod(type);
mapped = generic.Invoke(_umbracoMapper, new object[] { block });

This code uses the Type.GetType method to get the Type object for the specified type name then gets the Map method from the UmbracoMapper class, creates a generic method with the specified type using the MakeGenericMethod method, and finally invokes the generic method with the specified arguments using the Invoke method.

Majid Shahabfar
  • 4,010
  • 2
  • 28
  • 36
  • The above is great, but I run into trouble at `typeof(UmbracoMapper).GetMethod("Map")` with it complaining a lack of ambiguity as I need to have passed it the target type for it to decipher with Map method to use. – WNTR Jul 11 '23 at 10:28
  • @WNTR In that case, use `GetMethods()` instead (which returns an array of overloads) and then choose the right one by looking at the number of parameters. – PMF Jul 11 '23 at 11:34