RPM1984
RPM1984

Reputation: 73112

Create type parameter based on another value

Don't know if this has been asked before, so point me to another question if it has.

I've got a method like this:

private void SomeMethod<TLocation>(int x, int y) where TLocation : DataLocation
{
   //
}

In the method i wish to call it with, i have an enum, and i want to call the method with the type parameter.

public enum LocationType
{
   Country,
   State,
   County,
   City,
   Neighborhood,
   Street
}

Types of DataLocation:

DataCountry
DataState
DataCounty
DataCity
DataNeighborhood
DataStreet

Knowing that the type parameter is "Data" + enum name, is there any way i can dynamically call my method?

Or should i stick with:

switch (locationType)
{
   case LocationType.Country: 
      SomeMethod<DataCountry>(1, 2);
      break;
   case LocationType.State:
      SomeMethod<DataState>(2, 4);
      break;
   // etc
}

EDIT:

Looks like reflection is the only way. I'll be sticking with the switch.

Upvotes: 1

Views: 341

Answers (4)

Chris Shain
Chris Shain

Reputation: 51319

It sounds like this method should be defined as a member of the DataState class, and overridden accordingly, possibly with internal use of this.GetType(). You are kind of abusing generics here.

That said... (I almost hope I am downvoted for this...)

using System;
using System.Globalization;
using System.Linq;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            new ResolveIt<LocationType>().InvokeIt(LocationType.State, 1, 5);
            Console.ReadLine();
        }
    }

    public class ResolveIt<TEnum> // Unfortunately can't constrain on enums
    {
        private static readonly Action<int, int>[] Actions
            = Enum.GetValues(typeof(TEnum))
              .Cast<TEnum>()
              .Select(v => typeof(ResolveIt<TEnum>)
              .GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
              .First(n => n.Name == "SomeMethod")
              .GetGenericMethodDefinition()
              .MakeGenericMethod(new[] { Type.GetType(typeof(ResolveIt<TEnum>).Namespace + ".Data" + Enum.GetName(typeof(TEnum), v)) }))
              .Select(mi => (Action<int, int>)Delegate.CreateDelegate(typeof(Action<int, int>), mi))
              .ToArray();

        public void InvokeIt(TEnum type, int x, int y)
        {
            Actions[(Int32)Convert.ChangeType(type, typeof(Int32))](x, y);
        }

        private static void SomeMethod<TLocation>(int x, int y) where TLocation : DataLocation
        {
            Console.Out.WriteLine(typeof(TLocation));
        }
    }
    public enum LocationType { Country, State, City, Zip, }
    public class DataLocation { }
    public class DataCountry:DataLocation { }
    public class DataState:DataLocation { }
    public class DataCity:DataLocation { }
    public class DataZip:DataLocation { }
}

Upvotes: 0

DmitryG
DmitryG

Reputation: 17850

Here is the possible solution:

var dispatches = new Dictionary<LocationType, Action<int, int>>();
dispatches.Add(LocationType.Country, SomeMethod<DataCountry>);
dispatches.Add(LocationType.State, SomeMethod<DataState>);
//... and etc.

dispatches[LocationType.Country](1, 2); // the same as SomeMethod<DataCountry>(1,2)

Upvotes: 1

DotNetUser
DotNetUser

Reputation: 6612

You can always refactor your switch case and put case specific code in separate functions. Here is nice article about it- http://elegantcode.com/2009/01/10/refactoring-a-switch-statement/

Upvotes: 0

Scott Smith
Scott Smith

Reputation: 1863

I think you should stick with the implementation you suggested using the switch statement. It is clear and concise plus I am unaware of how you could do it dynamically.

Upvotes: 0

Related Questions