在运行时我得到某种类型的盒装实例。如何将其拆箱到基础类型?
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;
答案 0 :(得分:21)
如果您在编译时不知道类型,那么您无法取消装箱,因为您无处可放 - 您所能做的就是存储它在object
中,即:盒装。
同样适用于像string
这样的引用类型:如果在编译时不知道类型,则无法将其转换为正确的类型:无处可放< / em>的
你可以特殊情况下的几种类型,例如:
if(obj is int) {
int i = (int)obj;
...
} ...
另一个有时(不常见)有用的技巧是切换到 generics ;然后,不是用object
来谈论T
,而是用dynamic obj = ...
Foo(obj);
...
Foo<T>(T val) { ... code with T ... }
来谈论。这有......限制使用。最简单的方法是通过动态,例如:
Foo(string val) { ... code with string ...}
Foo(int val) { ... code with int ...}
您还可以为该appreach添加特殊情况:
{{1}}
但是,坦率地说,我建议最好仔细看看你想要做什么。
答案 1 :(得分:9)
现在让我们假设真正的拳击发生:
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
,你想使用哪种引用类型。
答案 2 :(得分:4)
在这种情况下,我将使用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);
}
}
答案 3 :(得分: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
答案 4 :(得分:1)
务实的解决方案;尝试直接使用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;
}
答案 5 :(得分:1)
使用表达式:
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);
}
答案 6 :(得分:0)
public static string GetType(object data)
{
Type type = data.GetType();
return Convert.ChangeType(data, type).GetType().Name;
}
嗨,此方法接收对象数据并返回对象的字符串类型名称。 希望这就是你所需要的。
答案 7 :(得分:-1)
您可以尝试使用动态运行时
[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";
}