【问题标题】:Cannot implicitly convert type 'Int' to 'T'无法将类型“Int”隐式转换为“T”
【发布时间】:2011-12-31 13:36:49
【问题描述】:

我可以拨打Get<int>(Stat);Get<string>(Name);

但是编译时我得到:

无法将类型“int”隐式转换为“T”

string 也是如此。

public T Get<T>(Stats type) where T : IConvertible
{
    if (typeof(T) == typeof(int))
    {
        int t = Convert.ToInt16(PlayerStats[type]);
        return t;
    }
    if (typeof(T) == typeof(string))
    {
        string t = PlayerStats[type].ToString();
        return t;
    }
}

【问题讨论】:

  • 你可能认为 if 块检查了 T 是 int,所以在块内,你知道 T 是 int,你应该能够将 int 隐式转换为 T。但是编译器不是设计的按照这个推理,它只知道通常 T 不是从 int 派生的,因此它不允许隐式转换。 (如果编译器支持它,验证器不会,因此编译的程序集将无法验证。)

标签: c# generics


【解决方案1】:

您应该可以只使用Convert.ChangeType() 而不是您的自定义代码:

public T Get<T>(Stats type) where T : IConvertible
{
    return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
}

【讨论】:

  • return (T)(object)PlayerStats[type];怎么样
  • @BrokenGlass 谢谢它运作良好。
  • @maxp becareful 它不适用于一般用途,例如强制转换非托管类型需要'Convert.ChangeType()'。
  • 比“你不应该”好得多
【解决方案2】:

任何时候你发现自己在泛型中打开一个类型你几乎肯定做错了什么。泛型应该是generic;它们应该以相同的方式运行完全独立于类型

如果 T 只能是 int 或 string,那么一开始就不要以这种方式编写代码。 编写两个方法,一个返回一个int,一个返回一个字符串。

【讨论】:

  • Get 其中汽车实现 IConvertible 会导致损坏。当有人看到你有一个泛型方法时,他们会假设他们可以传入任何实现 IConvertible 的东西。
  • 我只能部分同意你,@Eric。我有一种情况,我必须解析存储在 XML 标记中的数组。问题是 XML 文档遵循的规范(我的case) 说这样的数组不仅可以是 float、int 和 bool,还可以是一些自定义类型。但是,如果你得到一个 float[](array-tags 在其名称中包含存储数据的类型:float_array 存储浮点数),你需要将字符串解析为浮点数组,这需要使用一些 IFormatProvider)。我显然不能使用“T.Parse(...)”。所以对于一小部分情况,我需要使用这种切换。跨度>
  • 这个答案会让你远离兔子洞。我想为int, int?, bool, bool?, string 做一个通用函数,这似乎是不可能的。
  • 这使得通用枚举类型的开关变得实用。
  • 我不想用这个作为答案。但他是对的。我想检查类型,如果是特定类型,则在其上设置一个属性。解决方案是创建一个采用强类型参数的方法。
【解决方案3】:

其实你可以直接转换成object再转换成T

T var = (T)(object)42;

bool 的示例:

public class Program
{
    public static T Foo<T>()
    {
        if(typeof(T) == typeof(bool)) {
            return (T)(object)true;
        }

        return default(T);
    }

    public static void Main()
    {
        bool boolValue = Foo<bool>(); // == true
        string stringValue = Foo<string>(); // == null
    }
}

有时,这种行为是可取的。例如,当从基类或接口实现或覆盖泛型方法时,您想基于 T 类型添加一些不同的功能。

【讨论】:

    【解决方案4】:
    public T Get<T>(Stats type ) where T : IConvertible
    {
        if (typeof(T) == typeof(int))
        {
            int t = Convert.ToInt16(PlayerStats[type]);
            return (T)t;
        }
        if (typeof(T) == typeof(string))
        {
            string t = PlayerStats[type].ToString();
            return (T)t;
        }
    }
    

    【讨论】:

    • return (T) t; 因为不需要空检查。
    • 以上内容不会为我编译。 T 需要是“as”的引用类型才能编译。
    【解决方案5】:

    ChangeType 可能是您的最佳选择。我的解决方案类似于 BrokenGlass 提供的解决方案,带有一些 try catch 逻辑。

    static void Main(string[] args)
    {
        object number = "1";
        bool hasConverted;
        var convertedValue = DoConvert<int>(number, out hasConverted);
    
        Console.WriteLine(hasConverted);
        Console.WriteLine(convertedValue);
    }
    
    public static TConvertType DoConvert<TConvertType>(object convertValue, out bool hasConverted)
    {
        hasConverted = false;
        var converted = default(TConvertType);
        try
        {
            converted = (TConvertType) 
                Convert.ChangeType(convertValue, typeof(TConvertType));
            hasConverted = true;
        }
        catch (InvalidCastException)
        {
        }
        catch (ArgumentNullException)
        {
        }
        catch (FormatException)
        {
        }
        catch (OverflowException)
        {
        }
    
        return converted;
    }
    

    【讨论】:

    • 我的用例是从通用抽象类派生的具体类。该类被标记为抽象,因为它定义了一个抽象方法,该方法对基类的通用私有成员进行操作。泛型对其泛型类型使用 C# 7.3 Enum 约束。我刚刚成功完成了一项测试,它的工作方式与我希望的完全一样。
    【解决方案6】:

    试试这个:

    public T Get<T>(Stats type ) where T : IConvertible
    {
        if (typeof(T) == typeof(int))
        {
            return (T)(object)Convert.ToInt16(PlayerStats[type]);
    
        }
        if (typeof(T) == typeof(string))
        {
    
            return (T)(object)PlayerStats[type];
        }
    }
    

    【讨论】:

    • 感谢您的帮助,我的需求有所不同。我正在为现有的静态方法编写一个模拟方法,以便我可以对其进行测试。使用这个osherove.com/blog/2012/7/8/…
    【解决方案7】:

    考虑到@BrokenGlass 逻辑 (Convert.ChangeType) 不支持 GUID 类型。

    public T Get<T>(Stats type) where T : IConvertible
    {
        return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
    }
    

    错误:从“System.String”到“System.Guid”的无效转换。

    相反,通过添加System.ComponentModel 命名空间,使用TypeDescriptor.GetConverter 使用以下逻辑。

    public T Get<T>(Stats type) where T : IConvertible
    {
        (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(PlayerStats[type])
    }
    

    阅读this

    【讨论】:

      【解决方案8】:

      您似乎需要TypeConverter,请参阅this blog entry

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-02
        • 1970-01-01
        • 2011-02-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多