C #에서 제네릭 메서드 만들기


84

비슷한 방법을 여러 가지 일반적인 방법으로 결합하려고합니다. 쿼리 문자열의 값을 반환하는 여러 메서드가 있습니다. 해당 쿼리 문자열이 없거나 올바른 형식이 아닌 경우 null입니다. 모든 유형이 기본적으로 nullable이면 충분하지만 정수 및 날짜에는 nullable 제네릭 유형을 사용해야합니다.

여기 내가 지금 가지고있는 것입니다. 그러나 숫자 값이 유효하지 않고 불행히도 내 시나리오에서 유효한 값인 경우 0을 다시 전달합니다. 누군가 나를 도울 수 있습니까? 감사!

public static T GetQueryString<T>(string key) where T : IConvertible
{
    T result = default(T);

    if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
    {
        string value = HttpContext.Current.Request.QueryString[key];

        try
        {
            result = (T)Convert.ChangeType(value, typeof(T));  
        }
        catch
        {
            //Could not convert.  Pass back default value...
            result = default(T);
        }
    }

    return result;
}

그는 많은 구현을 포팅하고 있으므로 이전 기능을 호출하고 결과를 기억하고 새 기능을 호출하고 결과를 기억하고 비교합니다. 이제 무작위 입력으로 100 번 수행하면 짜잔!
Hamish Grubijan

죄송합니다.이 경우 어떻게 적용되는지 모르겠습니다. 나는 여전히 기능이 작동하도록 노력하고 있습니다.
Mike Cole

답변을 보면 약간 혼란 스럽습니다. 호출자가 int 또는 int를 사용하여 매개 변수화하고 있습니까? T로?

이것을 내부적으로 처리하는 대신 메서드가 예외를 throw하도록 허용해야하는 것처럼 보입니다. 어쩌면 그것은 나일 수도 있지만 ChangeType실패 할 때 생성되는 예외를 보지 못하기 때문에 호출이 항상 기본값을 반환하는 이유를 혼동 할 수 있습니다 .
crush

답변:


64

default (T)를 사용하는 대신 반환 할 기본값을 지정한 경우 어떻게됩니까?

public static T GetQueryString<T>(string key, T defaultValue) {...}

전화를 더 쉽게 할 수 있습니다.

var intValue = GetQueryString("intParm", Int32.MinValue);
var strValue = GetQueryString("strParm", "");
var dtmValue = GetQueryString("dtmPatm", DateTime.Now); // eg use today's date if not specified

단점은 유효하지 않거나 누락 된 쿼리 문자열 값을 나타 내기 위해 매직 값이 필요하다는 것입니다.


예, 이것은 정수의 기본값에 의존하는 것보다 더 실용적으로 보입니다. 나는 이것을 명심할 것이다. 제네릭이 아닌 함수를 사용하는 데 의지 할 수도 있지만 여전히 모든 유형에 대해 원래 함수가 작동하기를 바라고 있습니다.
Mike Cole

잘못된 정수에 대해 0이 아닌 다른 값을 반환하지 않는 이유는 무엇입니까? 유효한 값이 아니거나 이미 null과 같은 특수 목적이있는 원하는 것을 반환 할 수 있습니다. InvalidInteger 등의 고유 한 유형을 만들 수도 있습니다. 잘못된 쿼리 문자열에 대해 null을 반환하고 있습니까? 잘못된 정수에 대해서도 반환 할 수 있으므로 null은 단순히 '뭔가 나쁘고 나는 당신에게 가치가 없습니다'를 의미하고 함수에 대한 참조로 reasonCode를 전달할 수 있습니까?
Dan Csharpster

1
값을 얻는 방법 : long ? test기본값은 null이어야합니다.
Arshad

16

알아, 알아,하지만 ...

public static bool TryGetQueryString<T>(string key, out T queryString)

4
Try-pattern 잘 모든 .NET 개발자에게 알려 져야한다. 저에게 물어 보면 나쁜 것이 아닙니다. F # 또는 NET 4.0에서는 옵션 (또는 선택) 사용합니다
기독교 Klauser

6
다른 이유가 없다면, 출력 변수를 "사전 선언"해야하는 것을 싫어하기 때문에 피하려고합니다. 특히 사용되지 않는 경우에는-그렇지 않으면 완벽하게 좋은 코드 줄이었던 것을 낭비하는 것입니다.
Jay

실제로 문제를 해결하는 가장 간단한 방법입니다. 위와 같이 하나의 함수를 정의하고이 함수를 사용하는 두 명의 도우미를 정의합니다 (4 개의 라이너).
greenoldman

1
Jay가 말한 것과 같은 이유로 Try 패턴이 싫습니다. 가능한 한 하나의 일반적인 기능을 선호하는데, 이것이 원래 목표였습니다.
Mike Cole

11
하지 말거나 시도 할 수 없습니다! <Yoda>
Rabbit

12

이건 어때? 반환 유형을에서 T로 변경Nullable<T>

public static Nullable<T> GetQueryString<T>(string key) where T : struct, IConvertible
        {
            T result = default(T);

            if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
            {
                string value = HttpContext.Current.Request.QueryString[key];

                try
                {
                    result = (T)Convert.ChangeType(value, typeof(T));  
                }
                catch
                {
                    //Could not convert.  Pass back default value...
                    result = default(T);
                }
            }

            return result;
        }

오류 : 'T'형식은 제네릭 형식 또는 'System.Nullable <T>'메서드에서 매개 변수 'T'로 사용하려면 nullable이 아닌 값 형식이어야합니다.
Mike Cole

또한 지정해야합니다 where T : struct.
Aaronaught 2010-01-27

@Mike C : 동일한 오류가 발생해서는 안됩니다. 편집 된 코드는 확실히 컴파일됩니다.
Aaronaught

네, 지금 확인하세요. 그러면 String 유형에 대해 이것을 호출하고 싶을 때 어떻게됩니까? 지금은 받아들이지 않습니다.
Mike Cole

때문에 @MikeC, 즉 가능하다고 생각하지 않는다 stringA는 nullable
라비

5

어쩌면 어쩌면 모나드를 사용할 수 있습니다 (제이의 대답을 선호하지만)

public class Maybe<T>
{
    private readonly T _value;

    public Maybe(T value)
    {
        _value = value;
        IsNothing = false;
    }

    public Maybe()
    {
        IsNothing = true;
    }

    public bool IsNothing { get; private set; }

    public T Value
    {
        get
        {
            if (IsNothing)
            {
                throw new InvalidOperationException("Value doesn't exist");
            }
            return _value;
        }
    }

    public override bool Equals(object other)
    {
        if (IsNothing)
        {
            return (other == null);
        }
        if (other == null)
        {
            return false;
        }
        return _value.Equals(other);
    }

    public override int GetHashCode()
    {
        if (IsNothing)
        {
            return 0;
        }
        return _value.GetHashCode();
    }

    public override string ToString()
    {
        if (IsNothing)
        {
            return "";
        }
        return _value.ToString();
    }

    public static implicit operator Maybe<T>(T value)
    {
        return new Maybe<T>(value);
    }

    public static explicit operator T(Maybe<T> value)
    {
        return value.Value;
    }
}

방법은 다음과 같습니다.

    public static Maybe<T> GetQueryString<T>(string key) where T : IConvertible
    {
        if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
        {
            string value = HttpContext.Current.Request.QueryString[key];

            try
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
            catch
            {
                //Could not convert.  Pass back default value...
                return new Maybe<T>();
            }
        }

        return new Maybe<T>();
    }

4

Convert.ChangeType().NET 2.0 BCL에서 nullable 형식 또는 열거 형을 올바르게 처리하지 않습니다 (하지만 BCL 4.0에서는 수정되었다고 생각합니다). 외부 구현을 더 복잡하게 만들기보다는 변환기가 더 많은 작업을 수행하도록 만드십시오. 내가 사용하는 구현은 다음과 같습니다.

public static class Converter
{
  public static T ConvertTo<T>(object value)
  {
    return ConvertTo(value, default(T));
  }

  public static T ConvertTo<T>(object value, T defaultValue)
  {
    if (value == DBNull.Value)
    {
      return defaultValue;
    }
    return (T) ChangeType(value, typeof(T));
  }

  public static object ChangeType(object value, Type conversionType)
  {
    if (conversionType == null)
    {
      throw new ArgumentNullException("conversionType");
    }

    // if it's not a nullable type, just pass through the parameters to Convert.ChangeType
    if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
    {
      // null input returns null output regardless of base type
      if (value == null)
      {
        return null;
      }

      // it's a nullable type, and not null, which means it can be converted to its underlying type,
      // so overwrite the passed-in conversion type with this underlying type
      conversionType = Nullable.GetUnderlyingType(conversionType);
    }
    else if (conversionType.IsEnum)
    {
      // strings require Parse method
      if (value is string)
      {
        return Enum.Parse(conversionType, (string) value);          
      }
      // primitive types can be instantiated using ToObject
      else if (value is int || value is uint || value is short || value is ushort || 
           value is byte || value is sbyte || value is long || value is ulong)
      {
        return Enum.ToObject(conversionType, value);
      }
      else
      {
        throw new ArgumentException(String.Format("Value cannot be converted to {0} - current type is " +
                              "not supported for enum conversions.", conversionType.FullName));
      }
    }

    return Convert.ChangeType(value, conversionType);
  }
}

그러면 GetQueryString <T> 구현은 다음과 같습니다.

public static T GetQueryString<T>(string key)
{
    T result = default(T);
    string value = HttpContext.Current.Request.QueryString[key];

    if (!String.IsNullOrEmpty(value))
    {
        try
        {
            result = Converter.ConvertTo<T>(value);  
        }
        catch
        {
            //Could not convert.  Pass back default value...
            result = default(T);
        }
    }

    return result;
}

0

이 클래스 설정 {public int X {get; set;} public string Y {get; 세트; } // 필요에 따라 반복

 public settings()
 {
    this.X = defaultForX;
    this.Y = defaultForY;
    // repeat ...
 }
 public void Parse(Uri uri)
 {
    // parse values from query string.
    // if you need to distinguish from default vs. specified, add an appropriate property

 }

이것은 100 개의 프로젝트에서 잘 작동했습니다. 다른 많은 구문 분석 솔루션 중 하나를 사용하여 값을 구문 분석 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.