Подтвердить что ты не робот

С# Generics и проверка типов

У меня есть метод, который использует IList<T> как параметр. Мне нужно проверить, какой тип этого объекта T и что-то сделать на нем. Я пытался использовать значение T, но компилятор не разрешает его. Мое решение таково:

private static string BuildClause<T>(IList<T> clause)
{
    if (clause.Count > 0)
    {
        if (clause[0] is int || clause[0] is decimal)
        {
           //do something
        }
        else if (clause[0] is String)
        {
           //do something else
        }
        else if (...) //etc for all the types
        else
        {
           throw new ApplicationException("Invalid type");
        }
    } 
}

Должен быть лучший способ сделать это. Есть ли способ проверить тип T, который передается, а затем использовать оператор switch?

4b9b3361

Ответ 1

Вы можете использовать перегрузки:

public static string BuildClause(List<string> l){...}

public static string BuildClause(List<int> l){...}

public static string BuildClause<T>(List<T> l){...}

Или вы можете проверить тип общего параметра:

Type listType = typeof(T);
if(listType == typeof(int)){...}

Ответ 2

Вы можете использовать typeof(T).

private static string BuildClause<T>(IList<T> clause)
{
     Type itemType = typeof(T);
     if(itemType == typeof(int) || itemType == typeof(decimal))
    ...
}

Ответ 3

По умолчанию знаю, что нет отличного способа. В то же время я разочаровался в этом и написал небольшой полезный класс, который немного помог, и сделал синтаксис немного более чистым. По сути, он превращает код в

TypeSwitcher.Do(clause[0],
  TypeSwitch.Case<int>(x => ...),  // x is an int
  TypeSwitch.Case<decimal>(d => ...), // d is a decimal 
  TypeSwitch.Case<string>(s => ...)); // s is a string

Полный текст сообщения в блоге и сведения о реализации доступны здесь

Ответ 4

Тип оператора...

typeof(T)

... не будет работать с оператором switch С#. Но как насчет этого? Следующая публикация содержит статический класс...

Есть ли более эффективная альтернатива этому типу включения?

..., который позволит вам писать код следующим образом:

TypeSwitch.Do(
    sender,
    TypeSwitch.Case<Button>(() => textBox1.Text = "Hit a Button"),
    TypeSwitch.Case<CheckBox>(x => textBox1.Text = "Checkbox is " + x.Checked),
    TypeSwitch.Default(() => textBox1.Text = "Not sure what is hovered over"));

Ответ 5

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

Ответ 6

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

Например, если у вас есть класс, который, как говорят, реализован так (Примечание: я не показываю все, что этот код делает для простоты, и просто вырезал и вставлял сюда, чтобы он не мог строить или работать так, как предполагалось код делает, но он получает точку. Кроме того, Unit является перечислением):

public class FoodCount<TValue> : BaseFoodCount
{
    public TValue Value { get; set; }

    public override string ToString()
    {
        if (Value is decimal)
        {
            // Code not cleaned up yet
            // Some code and values defined in base class

            mstrValue = Value.ToString();
            decimal mdecValue;
            decimal.TryParse(mstrValue, out mdecValue);

            mstrValue = decimal.Round(mdecValue).ToString();

            mstrValue = mstrValue + mstrUnitOfMeasurement;
            return mstrValue;
        }
        else
        {
            // Simply return a string
            string str = Value.ToString() + mstrUnitOfMeasurement;
            return str;
        }
    }
}

...

public class SaturatedFat : FoodCountWithDailyValue<decimal>
{
    public SaturatedFat()
    {
        mUnit = Unit.g;
    }

}

public class Fiber : FoodCount<int>
{
    public Fiber()
    {
        mUnit = Unit.g;
    }
}

public void DoSomething()
{
       nutritionFields.SaturatedFat oSatFat = new nutritionFields.SaturatedFat();

       string mstrValueToDisplayPreFormatted= oSatFat.ToString();
}

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

Ответ 7

Вы можете сделать typeOf(T), но я бы дважды проверил ваш метод и убедился, что вы не нарушаете единую ответственность здесь. Это будет запах кода, и чтобы не говорить, что это не должно быть сделано, но вы должны быть осторожны.

Точка дженериков способна строить тип-агностические альгортимы, если вам не нравится, какой тип или до тех пор, пока он соответствует определенному набору критериев. Ваша реализация не очень общая.

Ответ 8

Невозможно использовать оператор switch для того, что вы хотите. Оператор switch должен быть снабжен интегральными типами, который не включает сложные типы, такие как объект типа или любой другой тип объекта.

Ответ 9

Как насчет этого:

            // Checks to see if the value passed is valid. 
            if (!TypeDescriptor.GetConverter(typeof(T)).IsValid(value))
            {
                throw new ArgumentException();
            }