Cast one dynamic to type another in C #

I'm trying to write a generic function that compares the expected results from reflection (but where the expectations are provided in the config by the users, not at design time) with the actual results for arbitrary properties.

I am having a problem where the expected type does not always reflect the default return type - eg. my reflection result (in dynamics) could be an int, where the expected result is an enum member (inheriting from int).

I would like to do the following:

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

      

however it doesn't seem to work. From messing around on the net, I managed to find that either System.Activator or Convert.ChangeType () might be my friends. However, so far they don't work as I expected - for example:

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

      

throws an exception (for the couple that is warning me of the problem), which Invalid cast from 'System.Int32' to 'Microsoft.Office.Core.MsoTriState'

- which I know is wrong because:

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

      

Note that while I could set a routine for MsoTriState (i.e. check for type this.CheckValue and explicit cast if applicable), I would prefer to do it in a way that works for unknown enum entries.

EDIT: Thanks for the comments below, I added a test before my tests of the form:

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

      

which fixes my immediate problem. I guess this combination with Convert.ChangeType()

(which, as I mentioned, doesn't seem to be like converting Enums to Ints) will cover most situations.

+3


source to share


1 answer


Types of time performing common language ( Boolean

, SByte

, Byte

...) realize IConvertible . Convert

works only on types that implement this interface. Switching between base types is not a problem. Enum is not a common language time type, but implements IConvertible

. This means that you can easily convert from Enum

to the base type with Convert.ChangeType

, but you cannot just do it backwards - there is no bridge between the two types. That's why you got caught Invalid cast from 'System.Int32' to 'Microsoft.Office.Core.MsoTriState'

. IConvertible

contains a method ( GetTypeCode

) that helps to get information about the base type Enum

. I wrote some code to solve your problem.

Decision

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;
        }
    }
}

      



Test code

[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)); 
    }
}

      

+2


source







All Articles