如何在编译时不知道该类型的情况下,从一个对象到它所包含的类型取消装箱

本文关键字:类型 一个对象 取消装箱 包含 情况下 编译 不知道 | 更新日期: 2023-09-27 18:05:29

在运行时,我得到了某种类型的装箱实例。如何将其取消包装为基础类型?

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; 

如何在编译时不知道该类型的情况下,从一个对象到它所包含的类型取消装箱

如果您在编译时不知道类型,则无法取消装箱,因为无处放置-您所能做的就是将其存储在object中,即:装箱。

这同样适用于string这样的引用类型:如果在编译时不知道类型,则无法将其强制转换为正确的类型:您无处放置。

可以特殊情况下的几种类型,例如:

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

有时(不经常(有用的另一个技巧是切换到泛型;那么你不是用CCD_ 3来说话,而是用T来说话。这已经。。。但使用有限。最简单的方法是通过动态,例如:

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

你也可以在这个apprepeach中添加特殊情况:

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

然而,坦率地说,我建议你最好仔细看看你想做什么。

现在让我们假设,真正的装箱发生了:

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,您希望使用什么引用类型。

在这种情况下,我将使用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);
    }
}

以下是您为什么要这样做的示例:

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

原因是该值是一个装箱对象。。。在运行时,您不知道类型,因此必须取消对道具的装箱。属性类型

实用的解决方案;尝试直接使用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;
}

使用表达式:

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);
}
public static string GetType(object data)
{
    Type type = data.GetType();
    return Convert.ChangeType(data, type).GetType().Name;
}

嗨,这个方法接收对象数据并返回对象的字符串类型名称。希望这正是你所需要的。

您可以尝试使用动态运行时

    [Test]
    public void Test_UnboxingAtRuntime()
    {
        object boxed = "Hello";
        //this line is commented out as it does not compile
        // OverloadedMethod(boxed);
        var result = CallCorrectMethod(boxed);
        Assert.That(result, Is.EqualTo("string"));
        boxed = 1;
        result = CallCorrectMethod(boxed);
        Assert.That(result, Is.EqualTo("int"));
    }
    public string CallCorrectMethod(dynamic t)
    {
        return OverloadedMethod(t);
    }
    public string OverloadedMethod(string s)
    {
        return "string";
    }
    public string OverloadedMethod(int s)
    {
        return "int";
    }
相关文章: