无拳击的通用解析方法

ben*_*wey 13 c# generics reflection

我正在尝试编写一个通用的Parse方法,该方法转换并返回NamedValueCollection中的强类型值.我尝试了两种方法,但这两种方法都通过装箱和拆箱来获得价值.有谁知道避免拳击的方法?如果你在生产中看到这个你会不喜欢它,它的性能有多糟糕?

Usuage:

var id = Request.QueryString.Parse<int>("id");
Run Code Online (Sandbox Code Playgroud)

尝试#1:

public static T Parse<T>(this NameValueCollection col, string key)
{
    string value = col[key];

    if (string.IsNullOrEmpty(value))
        return default(T);

    if (typeof(T) == typeof(int))
    {
        //return int.Parse(value); // cannot convert int to T
        //return (T)int.Parse(value); // cannot convert int to T
        return (T)(object)int.Parse(value); // works but boxes
    }
    if (typeof(T) == typeof(long))
    {
        return (T)(object)long.Parse(value); // works but boxes
    }
    ...

    return default(T);
}
Run Code Online (Sandbox Code Playgroud)

尝试#2(使用反射):

public static T Parse<T>(this NameValueCollection col, string key)
{
    string value = col[key];

    if (string.IsNullOrEmpty(value))
        return default(T);

    try
    {
        var parseMethod = typeof(T).GetMethod("Parse", new Type[] { typeof(string) });

        if (parseMethod == null)
            return default(T);

        // still boxing because invoke returns an object
        var parsedVal = parseMethod.Invoke(null, new object[] { value });
        return (T)parsedVal;
    }
    // No Proper Parse Method found
    catch(AmbiguousMatchException) 
    {
    }

    return default(T);
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*rth 34

public static T Parse<T>(this NameValueCollection col, string key)
{
  return (T)Convert.ChangeType(col[key], typeof(T));
}
Run Code Online (Sandbox Code Playgroud)

我不完全确定ChangeType框是不是(我想阅读文档会告诉我,但我现在时间紧迫),但至少它摆脱了所有类型检查.虽然拳击开销不是很高,所以我不会太担心它.如果您担心运行时类型的一致性,我会将函数编写为:

public static T Parse<T>(this NameValueCollection col, string key)
{
  T value;

  try
  {
    value = (T)Convert.ChangeType(col[key], typeof(T));
  }
  catch
  {
    value = default(T);
  }

  return value;
}
Run Code Online (Sandbox Code Playgroud)

这样,如果由于某种原因无法转换值,函数将不会弹出.这意味着,当然,您必须检查返回的值(无论如何您都必须这样做,因为用户可以编辑查询字符串).

  • 那不还是盒子吗?Convert.ChangeType 返回一个对象。 (3认同)

Rob*_*ner 8

我认为你过度估计拳击/拆箱的影响.解析方法将有更大的开销(字符串解析),使拳击开销相形见绌.此外,所有if语句都会产生更大的影响.反思对所有人产生了最大的影响.

我不希望在生产中看到这种代码,因为有一种更简洁的方法.我遇到的主要问题是需要覆盖所有案例的大量if语句以及有人可以将任何旧类型传递给它的事实.

我要做的是为我想要解析的每个类型编写一个解析函数(即ParseInt()).它更清晰,并且很好地定义了该函数将尝试做什么.此外,对于短静态方法,编译器更可能内联它们,从而保存函数调用.

我认为这是泛型的一个不好的应用,这样做的任何特殊原因?

  • 谢谢罗伯特,我发布这个的原因是因为事情看起来很腥.我要废弃这段代码.我应该采用KISS理论,而不是试图过度设计这个. (3认同)

xan*_*tos 5

我将添加一些未记录的方式:

public static T Convert<T>()
{
    if (typeof(T) == typeof(int))
    {
        int a = 5;
        T value = __refvalue(__makeref(a), T);
        return value;
    }
    else if (typeof(T) == typeof(long))
    {
        long a = 6;
        T value = __refvalue(__makeref(a), T);
        return value;
    }

    throw new NotImplementedException();
}
Run Code Online (Sandbox Code Playgroud)

关于它们的文档很少,但它们从 C# 4.0 开始工作。例如在这里阅读C# 的隐藏功能?请记住,无证意味着不受支持,等等等等将来无法工作等等等等,如果你使用它们,魔鬼会来找你等等:-)