web-dev-qa-db-ja.com

コンパイル時にそのタイプを知らずに、オブジェクトからオブジェクトに含まれるタイプにボックス化解除する方法は?

実行時に、あるタイプのボックス化されたインスタンスを取得します。基になるタイプにボックス化解除する方法は?

Object obj;
String variable = "Some text";

obj = variable // boxing;

// explicit unboxing, because we know the type of variable at compile time.

var x = (String)obj     

// Now let's pretend that we don't know the type of underlying object at compile time. 

Type desiredType = obj.GetType(); // But we can figure out.

//And now the question. 
//How to express something like this:

var y = (desiredType)obj; //Need to get unboxed instance of initial variable here; 
27
Paul Kyrejto

タイプがわからない場合コンパイル時の場合、ボックス化を解除することはできません配置する場所がありません -objectに格納するだけです、つまり:ボックス化されています。

同じことがstringのような参照型にも当てはまります。コンパイル時に型がわからない場合、正しい型にキャストすることはできません。置く場所がない

あなたcan特殊なケース、いくつかのタイプ、例:

if(obj is int) {
    int i = (int)obj;
    ...
} ...

時々(あまり頻繁ではない)役立つもう1つのトリックは、ジェネリックに切り替えることです。次に、objectの観点から話す代わりに、Tの観点から話します。これは...使用が制限されています。これを行う最も簡単な方法は、dynamicを使用することです。例:

dynamic obj = ...
Foo(obj);
...
Foo<T>(T val) { ... code with T ... }

そのアプローチに特別なケースを追加することもできます。

Foo(string val) { ... code with string ...}
Foo(int val) { ... code with int ...}

しかし、率直に言って、あなたがやろうとしていることを一生懸命に見たほうがよいかもしれません。

22
Marc Gravell

ここで、実際のボクシングが発生するとします。

int v = 5;

object o = v; //boxed 

Type type = o.GetType(); //will return typeof(int)

int convertedBack = (int)Convert.ChangeType(o, type);

Console.WriteLine (convertedBack); //prints 5

備考、代用する場合:

object convertedBack = Convert.ChangeType(o, type);

Console.WriteLine (convertedBack); //it still prints 5
Console.WriteLine (o); //it even print 5 here

その理由は、基になるオブジェクトがまだintであるためです。この例を使用して、ボクシングはここでは無関係であることを示しました。操作では何らかの抽象化に依存する必要があり、動的にintにキャストする場合は、どの参照型を使用しますか。

9
Ilya Ivanov

このような場合、Dictionary<Type, Action<object>>を使用して戦略パターンを使用します。

internal class Program
{
    private static void Main(string[] args)
    {
        var something = new Something();

        something.ComputeValue(13);
        something.ComputeValue(DateTime.Now);
        something.ComputeValue(DayOfWeek.Monday);

        Console.ReadKey();
    }
}

internal class Something
{
    private static Dictionary<Type, Action<object>> _Strategies;

    static Something()
    {
        // Prepare all available strategies.
        _Strategies = new Dictionary<Type, Action<object>>();
        _Strategies.Add(typeof(int), ComputeInteger);
        _Strategies.Add(typeof(DateTime), ComputeDateTime);
    }

    public void ComputeValue(object value)
    {
        Action<object> action;

        // Check if we have a matching strategy.
        if (!_Strategies.TryGetValue(value.GetType(), out action))
        {
            // If not, log error, throw exception, whatever.
            action = LogUnknownType;
        }

        // Perform the matching strategy on the given value.
        action(value);
    }

    private static void ComputeDateTime(object source)
    {
        // We get an object, but we are sure that it will always be an DateTime.
        var value = (DateTime)source;
        Console.WriteLine("We've got an date time: " + value);
    }

    private static void ComputeInteger(object source)
    {
        // We get an object, but we are sure that it will always be an int.
        var value = (int)source;
        Console.WriteLine("We've got an integer: " + value);
    }

    private static void LogUnknownType(object source)
    {
        // What should we do with the drunken sailor?
        var unknownType = source.GetType();
        Console.WriteLine("Don't know how to handle " + unknownType.FullName);
    }
}
4
Oliver

式を使用する:

var y = DynamicCast(obj、desiredType);

static object DynamicCast(object source, Type type)
{
    var parameter = Expression.Parameter(typeof(object), "input");

    var cast = Expression.TypeAs(Expression.Convert(parameter, type), typeof(object));

    var lambda = Expression.Lambda<Func<object, object>>(cast, parameter);

    var func = lambda.Compile();

    return func(source);
}
1
Rob Lans

実用的な解決策; TypeConverterを直接使用してみてください。失敗した場合は、文字列に変換してからもう一度使用してください。-

private static T GetValueOfType<T>(this ManagementBaseObject MBO, String FieldName) {
    T lResult;

    try {
        Object lObj = MBO[FieldName];

        var lSrcType = lObj.GetType();
        var lDestType = typeof(T);

        if (lDestType.IsValueType && lDestType.IsAssignableFrom(lSrcType)) {
            lResult = (T)lObj;
            return lResult;
        }

        var lDestTC = TypeDescriptor.GetConverter(typeof(T));
        if (lDestTC.CanConvertFrom(lSrcType)) {
            lResult = (T)lDestTC.ConvertFrom(lObj);
        } else {
            var lSrcTC = TypeDescriptor.GetConverter(lSrcType);
            String lTmp = lSrcTC.ConvertToInvariantString(lObj);
            lResult = (T)lDestTC.ConvertFromInvariantString(lTmp);
        }
    } catch {
        lResult = default(T);
    }
    return lResult;
}
1

これを行う理由の正確な例を次に示します。

class MyClass
{
   public int Id {get;set;}
   public string Name {get;set;}
   public decimal Val {get;set;}
}
int i = 0;
var myClassImp = new MyClass();
foreach (var val in new [object]{"10", "My name", "100.21"} // Could be read from some data source, such as an Excel spreadsheet
{
   var prop = typeof(MyClass).GetProperties().ElementAt(i++);
   // !!!!!! THROWS EXCEPTION  !!!!!!!
   prop.SetValue(myClassImp, System.Convert.ChangeType(val, prop.PropertyType), null);
}

これは、値がボックス化されたオブジェクトであるためです...実行時にタイプがわからないため、prop.PropertyTypeにボックス化解除する必要があります。

1
David Robinson
public static string GetType(object data)
{
    Type type = data.GetType();
    return Convert.ChangeType(data, type).GetType().Name;
}

こんにちは、このメソッドはオブジェクトデータを受け取り、オブジェクトの文字列型名を返します。これがあなたが必要なものであることを願っています。

0
Arman Veranyan