[c#] C # 제네릭 및 형식 검사

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문 을 사용할 수있는 방법이 있습니까?



답변

과부하를 사용할 수 있습니다.

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)){...}


답변

사용할 수 있습니다 typeof(T).

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


답변

기본적으로 좋은 방법이 없다는 것을 알고 있습니다. 얼마 전에 나는 이것에 실망했고 약간을 도왔고 구문을 조금 더 깔끔하게 만드는 약간의 유틸리티 클래스를 작성했습니다. 본질적으로 코드를

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

전체 블로그 게시물 및 구현에 대한 세부 정보는 여기에서 확인할 수 있습니다.


답변

그리고 C #이 발전했기 때문에 (이제) 패턴 일치를 사용할 수 있습니다 .

private static string BuildClause<T>(IList<T> clause)
{
    if (clause.Count > 0)
    {
        switch (clause[0])
        {
            case int x: // do something with x, which is an int here...
            case decimal x: // do something with x, which is a decimal here...
            case string x: // do something with x, which is a string here...
            ...
            default: throw new ApplicationException("Invalid type");
        }
    }
}

다시 C # 8.0의 스위치 식 을 사용하면 구문이 더욱 간결 해집니다.

private static string BuildClause<T>(IList<T> clause)
{
    if (clause.Count > 0)
    {
        return clause[0] switch
        {
            int x => "some string related to this int",
            decimal x => "some string related to this decimal",
            string x => x,
            ...,
            _ => throw new ApplicationException("Invalid type")
        }
    }
}


답변

typeof 연산자 …

typeof(T)

… c # 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"));


답변

유형을 확인하고 유형을 기반으로하는 작업을하는 모든 사람에게는 제네릭에 대한 좋은 생각이 아닙니다. 저는 동의하지만 이것이 완벽하게 이해되는 상황이있을 수 있다고 생각합니다.

예를 들어 이렇게 구현 된 클래스가있는 경우 (참고 :이 코드가 단순성을 위해 수행하는 모든 작업을 표시하지 않고 여기에 잘라 붙여 넣었으므로 전체 코드가 의도 한대로 빌드하거나 작동하지 않을 수 있지만 요점을 얻습니다. 또한 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();
}

요약하자면, 특별한 일을하기 위해 제네릭이 어떤 유형인지 확인하려는 타당한 이유가 있다고 생각합니다.


답변

원하는 작업에 switch 문을 사용할 수있는 방법이 없습니다. switch 문은 정수 유형과 함께 제공되어야합니다. 정수 유형은 “유형”개체와 같은 복합 유형이나 해당 문제에 대한 다른 개체 유형을 포함하지 않습니다.