0

I have a code like this:

  if (args.ElementType == typeof(SomeFirstClassName))
  {
    args.Result = GetResult<SomeFirstClassName>(args);
  }
  else if (args.ElementType == typeof(SomeSecondClassName))
  {
    args.Result = GetResult<SomeSecondClassName>(args);
  }

How I can simplify this code, if I will have a many types? For example, can I do something like below?

args.Result = this.GetResult<**args.ElementType**>(args);

I cannot put the variable Type (args.ElementType) to the <>. Is it limitation of C#?

Smit
  • 609
  • 3
  • 11
  • 27

2 Answers2

1

You simplify this without reflection by using a dictionary which maps the type to the method to call.

Here's a sample program to demonstrate:

using System;
using System.Collections.Generic;

namespace Demo
{
    public class SomeFirstClassName{}

    public class SomeSecondClassName{}

    public class Result {}

    public class Args
    {
        public Result Result;
        public Type   ElementType;
    }

    internal class Program
    {
        private Dictionary<Type, Func<Args, Result>> map = new Dictionary<Type, Func<Args, Result>>();

        private void run()
        {
            init();

            var args1 = new Args {ElementType = typeof(SomeFirstClassName)};
            var args2 = new Args {ElementType = typeof(SomeSecondClassName)};

            test(args1); // Calls GetResult<T> for Demo.SomeFirstClassName.
            test(args2); // Calls GetResult<T> for Demo.SomeSecondClassName.
        }

        private void test(Args args)
        {
            args.Result = map[args.ElementType](args);
        }

        private void init()
        {
            map.Add(typeof(SomeFirstClassName),  GetResult<SomeFirstClassName>);
            map.Add(typeof(SomeSecondClassName), GetResult<SomeSecondClassName>);
        }

        public Result GetResult<T>(Args args)
        {
            Console.WriteLine("GetResult<T>() called for T = " + typeof(T).FullName);
            return null;
        }

        private static void Main()
        {
            new Program().run();
        }
    }
}

This makes the call site much simpler (args.Result = map[args.ElementType](args);) but you will still have to add an initialiser for each type to the init() method, as shown above.

However this does at least move all the type logic into a single method (init()) which I think is a cleaner and more maintainable design.


However, I can't help but think that there is going to be a much better object-oriented solution to what you're trying to achieve. But we'd need a lot more information about what it is you want to do (this looks like it might be an X-Y problem at the moment).

Community
  • 1
  • 1
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
0

The answer to your question is to use reflection. However, if you are looking for a non-reflection way of getting around this then you could pass in ElementType in as a parameter

GetResult<TElementType, TArgs>(TElementType elementType, TArgs args)

This would reduce your code to a single call i.e. GetResult(args.ElementType, args). It's not great but it would give you what you want.

Community
  • 1
  • 1
James
  • 80,725
  • 18
  • 167
  • 237