【问题标题】:Generic Method Return Type as Type parameter通用方法返回类型作为类型参数
【发布时间】:2013-07-23 17:48:59
【问题描述】:

我有一个可以将字符串值转换为各种类型的扩展方法,它看起来像这样:

public static T ToType<T> (this string value, T property)
    {
        object parsedValue = default(T);
        Type type = property.GetType();

        try
        {
            parsedValue = Convert.ChangeType(value, type);
        }
        catch (ArgumentException e)
        {
            parsedValue = null;
        }

        return (T)parsedValue;
    }

我对调用该方法时的外观不满意,但是:

myObject.someProperty = stringData.ToType(myObject.someProperty);

仅仅为了获取属性的类型而指定属性似乎是多余的。我宁愿使用这样的签名:

public static T ToType<T> (this string value, Type type) { ... }

并让 T 最终成为类型的类型。这将使调用更清晰:

myObject.someProperty = stringData.ToType(typeof(decimal));

但是,当我尝试以这种方式调用时,编辑器抱怨无法从使用情况中推断出扩展方法的返回类型。我可以将 T 链接到 Type 参数吗?

我错过了什么?

谢谢

【问题讨论】:

  • 我可以将 T 链接到 Type 参数吗? — 不能直接¹。您正在混淆编译时和运行时。当 C# 编译器在编译代码时处理对 ToType 的调用时,必须确定 T 是什么。 OTOH type 每次调用 ToType 时都会假定一个可能不同的值。 -------------------------------------------------- ------- ¹ — 您可以使用其中一种动态编译,但它是一种先进的技术,最好保留在真正需要的少数情况下。
  • 感谢大家的回答和意见。

标签: c# .net generics


【解决方案1】:

这就是你要找的吗?对于演员表无效的情况,我添加了一个额外的捕获

Decimal i = stringName.ToType<Decimal>();

public static T ToType<T>(this string value)
{
     object parsedValue = default(T);
     try
     {
         parsedValue = Convert.ChangeType(value, typeof(T));
     }
     catch (InvalidCastException)
     {
         parsedValue = null;
     }
     catch (ArgumentException)
     {
         parsedValue = null;
     }
     return (T)parsedValue;
} 

编辑

修复安东评论的捷径

if (typeof(T).IsValueType)
   return default(T);

【讨论】:

  • “具体指定类型参数”正是他在代码的第一行所做的。这是一种使用尖括号的特殊方法调用语法,尽管它应该适用于您的情况。
  • 对不起,赛斯。有用。我在电话中省略了
  • @Sayse btw 你的代码有问题,如果T 是值类型,则null 不能转换为T。通常的解决方法是使用此方法的两个版本,一个用于返回 T? 的值类型,另一个用于返回 T 的引用类型。
  • @AntonTykhyy - 你是对的,我没有用值类型测试过这个,虽然我不相信 OP 正在使用它们,谢谢
  • 预期类型之一是十进制,我已更新异常路径以将 parsedValue 恢复为默认值(T)
【解决方案2】:

为什么要使用属性?只需更改将类型变量设置为泛型类型的方式即可。

    public static T ToType<T>(this string value)
    {
        object parsedValue = default(T);
        Type type = typeof(T);

        try
        {
            parsedValue = Convert.ChangeType(value, type);
        }
        catch (ArgumentException e)
        {
            parsedValue = null;
        }

        return (T) parsedValue;
    }

用法:

myObject.someProperty = stringData.ToType<decimal>()

【讨论】:

  • 啊哈!我忘了在调用中指定 T ... ToType()!这行得通。谢谢!
【解决方案3】:

我将其用于通用转换:

    public bool ConvertTo<T>(object from, out T to) {
        to = default(T);
        if (from is T) { to = (T)from; return true; }                                           
        Type t = typeof(T);
        //TypeConverter converter = p.converter == null ? TypeDescriptor.GetConverter(t) : p.converter;
        TypeConverter converter = TypeDescriptor.GetConverter(t);
        if ((converter != null) && (converter.CanConvertTo(t))) {
            try { to = (T)converter.ConvertTo(null, culture, from, t); return true; }
            catch { }
        }
        try { to = (T)Convert.ChangeType(from, t, culture); return true; }
        catch { }
        return false;                                                                                       
    }

    public bool ConvertTo(object from, out object to, Type type) {
        to = null;
        if (from.GetType() == type) { to = from; return true; }     
        TypeConverter converter = TypeDescriptor.GetConverter(type);
        if ((converter != null) && (converter.CanConvertTo(type))) {
            try { to = converter.ConvertTo(null, culture, from, type); return true; }
            catch { }
        }
        try { to = Convert.ChangeType(from, type, culture); return true; }
        catch { }
        return false;                                           
    }

在调用Convert.ChangeType 之前,它会检查给定变量是否有TypeConverter

这样称呼:

int i = 123;
string s;
if (ConvertTo<string>(i, out s) {
    // use s
}

【讨论】:

    猜你喜欢
    • 2020-11-22
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 2015-07-18
    • 2018-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多