developer tip

C # 제네릭 및 형식 검사

copycodes 2020. 11. 4. 08:06
반응형

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

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


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"));

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


당신의 구성은 일반적인 방법의 목적을 완전히 무너 뜨립니다. 그것이 무엇인지 알아 내기에 충분한 정보를 우리에게주지는 않았지만, 당신이 성취하려는 것을 성취하기위한 더 나은 방법이 있어야하기 때문에 그것은 의도적으로 추한 것입니다.


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

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

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


그리고 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");
        }
    }
}

You can do typeOf(T), but I would double check your method and make sure your not violating single responsability here. This would be a code smell, and that's not to say it shouldn't be done but that you should be cautious.

The point of generics is being able to build type-agnostic algorthims were you don't care what the type is or as long as it fits within a certain set of criteria. Your implementation isn't very generic.


How about this :

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

I hope you find this helpful:

  • typeof(IList<T>).IsGenericType == true
  • typeof(IList<T>).GetGenericTypeDefinition() == typeof(IList<>)
  • typeof(IList<int>).GetGenericArguments()[0] == typeof(int)

https://dotnetfiddle.net/5qUZnt

참고URL : https://stackoverflow.com/questions/982952/c-sharp-generics-and-type-checking

반응형