Создать параметр типа на основе другого значения - PullRequest
1 голос
/ 25 января 2012

Не знаю, задавался ли этот вопрос раньше, поэтому укажите мне на другой вопрос, если он задан.

У меня есть такой метод:

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

В методе, с которым я хочу вызвать его, у меня есть enum , и я хочу вызвать метод с параметром типа.

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

Типы расположения данных:

DataCountry
DataState
DataCounty
DataCity
DataNeighborhood
DataStreet

Зная, что параметром типа является "Data" + enum name, есть ли способ, которым я могу динамически вызывать мой метод?

Или я должен придерживаться:

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

EDIT:

Похоже, отражение - единственный способ. Я буду придерживаться переключателя.

Ответы [ 4 ]

1 голос
/ 25 января 2012

Вот возможное решение:

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)
0 голосов
/ 25 января 2012

Вы всегда можете выполнить рефакторинг своего регистра переключателя и поместить код для конкретного регистра в отдельные функции. Вот хорошая статья об этом - http://elegantcode.com/2009/01/10/refactoring-a-switch-statement/

0 голосов
/ 25 января 2012

Похоже, этот метод должен быть определен как член класса DataState и соответственно переопределен, возможно, с внутренним использованием this.GetType(). Вы здесь злоупотребляете дженериками.

Это сказало ... (Я почти надеюсь, что за это проголосовали ...)

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 { }
}
0 голосов
/ 25 января 2012

Я думаю, вам следует придерживаться предложенной вами реализации, используя оператор switch.Это ясно и кратко, плюс я не знаю, как вы могли бы сделать это динамически.

...