在C#中创建泛型方法

Mik*_*ole 72 c# generics

我试图将一堆类似的方法组合成一个通用方法.我有几个方法返回查询字符串的值,如果该查询字符串不存在或格式不正确,则返回null.如果所有类型都是本机可空的,那么这很容易,但我必须使用可空的泛型类型来表示整数和日期.

这就是我现在拥有的.但是,如果数值无效,它将传回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;
}
Run Code Online (Sandbox Code Playgroud)

Wil*_*ill 59

如果您指定要返回的默认值,而不是使用默认值(T),该怎么办?

public static T GetQueryString<T>(string key, T defaultValue) {...}
Run Code Online (Sandbox Code Playgroud)

它也使它更容易调用:

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

缺点是你需要魔术值来表示无效/缺失的查询字符串值.


Jay*_*Jay 14

我知道,我知道,但......

public static bool TryGetQueryString<T>(string key, out T queryString)
Run Code Online (Sandbox Code Playgroud)

  • 做或者不做,不可以尝试!<尤达> (11认同)
  • 如果没有其他原因,我试图避免它,因为我讨厌必须"预先声明"那个输出变量,特别是如果它从来没有被使用过 - 浪费了本来可能是完美的代码行. (6认同)
  • 任何.NET开发人员都应该熟知`Try`模式.如果你问我,这不是一件坏事.在F#或NET 4.0中,您将使用Option(或Choice) (3认同)

Gra*_*ton 11

那这个呢?将返回类型更改TNullable<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;
        }
Run Code Online (Sandbox Code Playgroud)


Sam*_*Sam 5

Convert.ChangeType()无法正确处理 .NET 2.0 BCL 中的可空类型或枚举(但我认为它已在 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);
  }
}
Run Code Online (Sandbox Code Playgroud)

那么 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;
}
Run Code Online (Sandbox Code Playgroud)


Art*_*rov 5

你可以使用某种Maybe monad(虽然我更喜欢Jay的回答)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

你的方法看起来像:

    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>();
    }
Run Code Online (Sandbox Code Playgroud)