7

2 つの型がsourceTypeありtargetType、C# でメソッドを記述する必要があります。このメソッドは、 の値をsourceTypeの変数に代入できるかどうかを確認しますtargetType。関数のシグネチャはMatchResultTypeAndExpectedType(Type sourceType, Type targetType).

継承はIsAssignableFromによってカバーされます。変換可能な型の場合、 CanConvertFromを使用することを考えましたが、たとえば両方の型が数値の場合、常に を返しますfalse。私が行ったテスト:

TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(Decimal));
Console.WriteLine("Int16 to Decimal - " + typeConverter.CanConvertFrom(typeof(Int16)));
Console.WriteLine("UInt16 to Decimal - " + typeConverter.CanConvertFrom(typeof(UInt16)));

typeConverter = TypeDescriptor.GetConverter(typeof(long));
Console.WriteLine("UInt16 to Int64 - " + typeConverter.CanConvertFrom(typeof(uint)));

typeConverter = TypeDescriptor.GetConverter(typeof(Double));
Console.WriteLine("UInt16 to Double - " + typeConverter.CanConvertFrom(typeof(UInt16)));

typeConverter = TypeDescriptor.GetConverter(typeof(String));
Console.WriteLine("UInt16 to String - " + typeConverter.CanConvertFrom(typeof(UInt16)));

結果は次のとおりです。

Int16 to Decimal - False
UInt16 to Decimal - False
UInt16 to Int64 - False
UInt16 to Double - False
UInt16 to String - False

[編集]だから私の質問: .NET で、値を知らなくても、特定の型の値を別の型の変数に割り当てることができるかどうか、たとえば、暗黙的な変換が成功するかどうかを確認する方法はありますか? の実装に関するより具体的な要件MatchResultTypeAndExpectedType(Type sourceType, Type targetType):

  1. アセンブリは後で読み込まれるため、ソースとターゲットの型はコンパイル時にはわかりません。
  2. 値またはオブジェクトを入力として提供することはできません。
  3. システムの残りの部分では許可されていないため、このタイプのオブジェクトを実装で作成することはできません。値型の値を作成できます。
  4. 暗黙的な変換のみをチェックする必要があります。

sourceType値型かどうかはわかっています。したがって、メソッドのシグネチャは次のようになりますMatchResultTypeAndExpectedType(Type sourceType, Boolean isSourceValueType, Type targetType)

1 つの方法はImplicit Numeric Conversions Tableを実装することですが、他の変換やユーザー定義の変換には対応していません。

4

3 に答える 3

9

暗黙的/明示的な変換に関する問題は、コンパイル時に解決されることです。したがって、(私の知る限り)単純な実行時チェックはありません。ただしdynamic実装によってそれらが選択され、実行時に呼び出されます。(醜いですが) 変換を実行しようとするクラスを作成し、失敗した場合は例外をキャッチし、成功したかどうかを報告できます。

public class TypeConverterChecker<TFrom, TTo>
{
    public bool CanConvert { get; private set; }

    public TypeConverterChecker(TFrom from)
    {
        try
        {
            TTo to = (TTo)(dynamic)from;
            CanConvert = true;
        }
        catch
        {
            CanConvert = false;
        }
    }
}

次のようないくつかのクラスがあるとします。

public class Foo
{
    public static implicit operator Bar(Foo foo)
    {
        return new Bar();
    }

    public static implicit operator Foo(Bar bar)
    {
        return new Foo();
    }
}

public class Bar
{
}

public class Nope
{

}

使用法:

Console.WriteLine((new TypeConverterChecker<Foo, Bar>(new Foo())).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<Bar, Foo>(new Bar())).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<Foo, Nope>(new Foo())).CanConvert); //False

そして、あなたがテストしたタイプで:

Console.WriteLine((new TypeConverterChecker<Int16, Decimal>(0)).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<UInt16, Decimal>(0)).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<UInt16, Int64>(0)).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<UInt16, Double>(0)).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<UInt16, String>(0)).CanConvert); //False

これをより効率的に変更できると想像できます (結果を静的にキャッシュするため、同じTFrom, TTo組み合わせの後続のルックアップで変換を試行する必要はありません。値型は入力インスタンスをキャストする必要を無視するためです (単に を使用しますdefault(TFrom))) 。すべての変換がパスするため、 forを渡すべきではないことに注意してください (値型への変換でない限り)。nullTFrom fromnull

また、 Convert.ChangeTypeメソッドtry/catchを使用して1 秒を追加して、型に利用可能な実装が定義されているかどうかを確認することもできます。(後で実行する必要がある変換の種類がわかるように、これを別のブール値フラグとして保存することもできます)IConvertable

編集:コンパイル時にタイプがわからない場合は、少しのリフレクションを利用して、変換チェッカーを引き続き活用できます。

public static class TypeConverterChecker
{
    public static bool Check(Type fromType, Type toType, object fromObject)
    {
        Type converterType = typeof(TypeConverterChecker<,>).MakeGenericType(fromType, toType);
        object instance = Activator.CreateInstance(converterType, fromObject);
        return (bool)converterType.GetProperty("CanConvert").GetGetMethod().Invoke(instance, null);
    }
}

あなたの使い方は次のようになります:

object unknownObject = new Foo();
Type targetType = typeof(Bar);
Type sourceType = unknownObject.GetType();
Console.WriteLine(TypeConverterChecker.Check(sourceType, targetType, unknownObject));

targetType = typeof(Nope);
Console.WriteLine(TypeConverterChecker.Check(sourceType, targetType, unknownObject));
于 2013-07-16T12:58:27.913 に答える