首页 文章

在c#中将一个动态转换为另一个的类型

提问于
浏览
3

我正在尝试编写一个泛型函数,用于比较反射的预期结果(但是用户在配置中而不是在设计时提供期望值)与任意属性的实际结果进行比较 .

我遇到了一个问题,默认情况下预期的类型并不总是反映返回的类型 - 例如我的反射结果(在动态中)可能是一个int,其中预期的结果是枚举成员(从int继承) .

我想,因此要做到以下几点:

if ((dCurrentValue as typeof(this.CheckValue)) != this.CheckValue) { oOut = false; }

但是,这似乎不起作用 . 从网络上的笨拙,我已经设法发现System.Activator或Convert.ChangeType()可能是我的朋友 . 然而,到目前为止,他们没有像我期望的那样工作 - 例如:

dCurrentValue = Convert.ChangeType(dCurrentValue, this.CheckValue.GetType());

抛出一个异常(对于提醒我这个问题的那一对) Invalid cast from 'System.Int32' to 'Microsoft.Office.Core.MsoTriState' - 我知道这是错的,因为:

(int)Microsoft.Office.Core.MsoTriState.msoTrue == -1                                    // true
((Microsoft.Office.Core.MsoTriState)(-1)) == Microsoft.Office.Core.MsoTriState.msoTrue  // true

注意虽然我可以放入一个垫片来解决MsoTriState(即检查this.CheckValue的类型,如果适用的话显式转换),我宁愿这样做也适用于未知的枚举条目 .

编辑:感谢下面的评论,我在测试表单之前添加了一个测试:

if (((Type) this.CheckValue.GetType()).IsEnum)
{
    dCurrentValue = Enum.Parse(this.CheckValue.GetType(), dCurrentValue.ToString());
}

这解决了我的直接问题 . 我猜这个结合 Convert.ChangeType() (因为我似乎喜欢将Enums转换为Ints)将涵盖大多数情况 .

1 回答

  • 2

    公共语言运行时类型( BooleanSByteByte ...)实现IConvertible . Convert 仅适用于实现此接口的类型 . 基类型之间的转换不是问题 . Enum不属于公共语言运行库类型,但它实现 IConvertible . 这意味着您可以使用 Convert.ChangeType 轻松地从 Enum 转换为基本类型,但您不能简单地向后执行 - 这两种类型之间没有桥梁 . 这就是你 grab Invalid cast from 'System.Int32' to 'Microsoft.Office.Core.MsoTriState' 的原因 . IConvertible 包含方法( GetTypeCode ),它有助于获取有关 Enum 的基本类型的信息 . 我写了一些代码来解决你的问题 .

    解决方案

    public static class Comparer
    {
        public static IConvertible CastToConvertible<T>(T value)
        {
            if (value is IConvertible)
            {
                return (IConvertible)Convert.ChangeType(value, ((IConvertible)value).GetTypeCode());
            }
            // this type is not supported
            throw new ArgumentException("Unknown type: " + value.GetType());
        }
    
        public static bool Equals<T1, T2>(T1 first, T2 second)
        {
            try
            {
                IConvertible firstConveted = CastToConvertible(first);
                IConvertible secondConverted = CastToConvertible(second);
                // standard Equals cannot compare two different types,
                // so here the second value is
                // converted to the type of the first value
                var secondChangedType = (IConvertible)Convert.ChangeType(
                    secondConverted, firstConveted.GetTypeCode());
                return firstConveted.Equals(secondChangedType);
            }
            catch (Exception)
            {   
                // an exception might be caught in two cases:
                // 1. One of the values cannot be converted
                // to IConvertible interface.
                // 2. The second value cannot be converted 
                // to the type of the first value.
                return false;
            }
        }
    }
    

    测试代码

    [TestClass]
    public class ComparerTests
    {
        public enum ByteEnum : byte
        {
            One = 1, Two = 2
        }
    
        public enum IntEnum
        {
            One = 1, Two = 2, MegaLarge = 100500
        }
    
        [TestMethod]
        public void EqualsTest()
        {
            Assert.IsTrue(Comparer.Equals(2, 2));
            Assert.IsFalse(Comparer.Equals(1,2));
            Assert.IsTrue(Comparer.Equals(1, IntEnum.One));
            Assert.IsFalse(Comparer.Equals(1, IntEnum.Two));
            Assert.IsTrue(Comparer.Equals(ByteEnum.One, IntEnum.One));
            Assert.IsFalse(Comparer.Equals(ByteEnum.One, IntEnum.Two));
            Assert.IsFalse(Comparer.Equals(ByteEnum.One, IntEnum.MegaLarge)); 
        }
    }
    

相关问题