簡體   English   中英

在c#中將一個動態轉換為另一個的類型

[英]Cast one dynamic to the type of another in c#

我正在嘗試編寫一個泛型函數,用於比較反射的預期結果(但是用戶在配置中而不是在設計時提供期望值)與任意屬性的實際結果進行比較。

我遇到了一個問題,其中默認情況下期望的類型並不總是反映返回的類型 - 例如我的反射結果(在動態中)可能是一個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)將涵蓋大多數情況。

公共語言運行時類型( BooleanSByteByte ...)實現IConvertible Convert僅適用於實現此接口的類型。 基類型之間的轉換不是問題。 枚舉不屬於公共語言運行時類型,但它實現了IConvertible 這意味着您可以使用Convert.ChangeType輕松地從Enum轉換為基本類型,但您不能簡單地向后執行 - 這兩種類型之間沒有橋接 這就是為什么你Invalid cast from 'System.Int32' to 'Microsoft.Office.Core.MsoTriState'捕獲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)); 
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM