如何从对象中取消对它包含的类型,在编译时不知道该类型?

在运行时我得到某种类型的盒装实例。 如何将其拆箱到基础类型?

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

有时 (通常)有用的另一个技巧是转换为generics ; 然后,而不是谈论你正在谈论的object T 这有……限制使用。 最简单的方法是通过动态 ,例如:

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

您还可以为该appreach添加特殊情况:

 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>来使用策略模式:

 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> _Strategies; static Something() { // Prepare all available strategies. _Strategies = new Dictionary>(); _Strategies.Add(typeof(int), ComputeInteger); _Strategies.Add(typeof(DateTime), ComputeDateTime); } public void ComputeValue(object value) { Action 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); } 

原因是因为值是一个盒装对象…在运行时你不知道类型,所以你必须取消装箱到prop.PropertyType

务实的解决方案; 尝试直接使用TypeConverter,如果失败,转换为字符串并再次返回: –

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

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

使用表达式:

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>(cast, parameter); var func = lambda.Compile(); return func(source); } 

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

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