Как использовать коммутационный футляр на Type?

Возможный дубликат:
Есть ли более эффективная альтернатива этому типу включения?

Мне нужно перебирать все свойства моего класса и проверять, есть ли его тип int, который я должен что-то сделать, если его строка... затем сделайте что-нибудь. Мне нужно это с помощью коммутационного футляра. Здесь я использую переключатель следующим образом, но он запрашивает некоторую константу. см. следующий код:

 public static bool ValidateProperties(object o)
{
    if(o !=null)
    {
        var sourceType = o.GetType();
        var properties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Static);
        foreach (var property in properties)
        {
            var type = property.GetType();
            switch (type)
            {
                *case typeof(int):* getting error here
                    // d
            }
        }
    }
}

Также я хочу знать, какую проверку следует использовать, typeof (int) или typeof (Int32)?

Ответ 1

Вы не можете использовать блок переключателей для проверки значений типа Type. Компиляция вашего кода должна дать вам сообщение об ошибке:

Выражение оператора switch или case должно быть bool, char, string, интеграл, перечисление или соответствующий нулевой тип

Вместо этого вам нужно использовать инструкции if - else.

Также: typeof(int) и typeof(Int32) эквивалентны. int - это ключевое слово, а Int32 - имя типа.

UPDATE

Если вы ожидаете, что большинство типов будут внутренними, вы можете повысить производительность, используя блок переключателей с Type.GetTypeCode(...).

Например:

switch (Type.GetTypeCode(type))
{
    case TypeCode.Int32:
        // It an int
        break;

    case TypeCode.String:
        // It a string
        break;

    // Other type code cases here...

    default:
        // Fallback to using if-else statements...
        if (type == typeof(MyCoolType))
        {
            // ...
        }
        else if (type == typeof(MyOtherType))
        {
            // ...
        } // etc...
}

Ответ 2

Хорошим и расширяемым способом сделать это является создание словаря типов и делегатов соответствующего типа на основе того, что вы хотите делать со значениями этого типа.

Например:

var typeProcessorMap = new Dictionary<Type, Delegate>
{
    { typeof(int), new Action<int>(i => { /* do something with i */ }) },
    { typeof(string), new Action<string>(s => { /* do something with s */ }) },
};

И затем:

void ValidateProperties(object o)
{
    var t = o.GetType();
    typeProcessorMap[t].DynamicInvoke(o); // invoke appropriate delegate
}

Это решение расширяемо, настраивается даже во время выполнения, и до тех пор, пока вы сохраняете ключи и типы значений делегата в typeProcessorMap правильно подобранным, также безопасно.

Посмотрите на действие.

Ответ 3

Этот "ответ" - это проработка ответа Джона. (Маркировка CW)

Для записи DynamicInvoke немного медленнее. Чтобы проиллюстрировать это, рассмотрим следующую программу:

void Main()
{
    Func<int, string> myFunc = i => i.ToString();
    myFunc.DynamicInvoke(1);   // Invoke once so initial run costs are not considered
    myFunc(1);

    Stopwatch stopwatch = new Stopwatch();

    stopwatch.Start();
    for (int i = 0; i < 1000000; i++)
        myFunc.DynamicInvoke(1);
    stopwatch.Stop();

    var elapsed = stopwatch.Elapsed;

    stopwatch.Restart();
    for (int i = 0; i < 1000000; i++)
        myFunc(1);
    stopwatch.Stop();

    var elapsed2 = stopwatch.Elapsed;

    Console.WriteLine("DynamicInvoke: " + elapsed);
    Console.WriteLine("Direct Invocation: " + elapsed2);
}

Распечатывает:

DynamicInvoke: 00: 00: 03.1959900
Прямой вызов: 00: 00: 00.0735220

Это означает, что DynamicInvoke (в этом простом случае) в 42 раза медленнее прямого вызова.

Ответ 4

Обычно самым простым решением является включение имени типа:

switch (type.Name)
{
    case "Int32":
    ...
}