C# 使用类型变量转换变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/972636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Casting a variable using a Type variable
提问by theringostarrs
In C# can I cast a variable of type object to a variable of type T where T is defined in a Type variable?
在 C# 中,我可以将 object 类型的变量转换为 T 类型的变量,其中 T 在 Type 变量中定义吗?
采纳答案by Zyphrax
Here is an example of a cast and a convert:
这是一个强制转换和转换的示例:
using System;
public T CastObject<T>(object input) {
return (T) input;
}
public T ConvertObject<T>(object input) {
return (T) Convert.ChangeType(input, typeof(T));
}
Edit:
编辑:
Some people in the comments say that this answer doesn't answer the question. But the line (T) Convert.ChangeType(input, typeof(T))
provides the solution. The Convert.ChangeType
method tries to convert any Object to the Type provided as the second argument.
评论里有人说这个答案没有回答问题。但这条线(T) Convert.ChangeType(input, typeof(T))
提供了解决方案。该Convert.ChangeType
方法尝试将任何对象转换为作为第二个参数提供的类型。
For example:
例如:
Type intType = typeof(Int32);
object value1 = 1000.1;
// Variable value2 is now an int with a value of 1000, the compiler
// knows the exact type, it is safe to use and you will have autocomplete
int value2 = Convert.ChangeType(value1, intType);
// Variable value3 is now an int with a value of 1000, the compiler
// doesn't know the exact type so it will allow you to call any
// property or method on it, but will crash if it doesn't exist
dynamic value3 = Convert.ChangeType(value1, intType);
I've written the answer with generics, because I think it is a very likely sign of code smell when you want to cast a something
to a something else
without handling an actual type. With proper interfaces that shouldn't be necessary 99.9% of the times. There are perhaps a few edge cases when it comes to reflection that it might make sense, but I would recommend to avoid those cases.
我已经用泛型写了答案,因为我认为当您想a something
在a something else
不处理实际类型的情况下强制转换时,这很可能是代码异味的迹象。99.9% 的情况下都不需要适当的接口。当涉及到反射时,可能有一些边缘情况可能有意义,但我建议避免这些情况。
Edit 2:
编辑2:
Few extra tips:
一些额外的提示:
- Try to keep your code as type-safe as possible. If the compiler doesn't know the type, then it can't check if your code is correct and things like autocomplete won't work. Simply said: if you can't predict the type(s) at compile time, then how would the compiler be able to?
- If the classes that you are working with implement a common interface, you can cast the value to that interface. Otherwise consider creating your own interface and have the classes implement that interface.
- If you are working with external libraries that you are dynamically importing, then also check for a common interface. Otherwise consider creating small wrapper classes that implement the interface.
- If you want to make calls on the object, but don't care about the type, then store the value in an
object
ordynamic
variable. - Genericscan be a great way to create reusable code that applies to a lot of different types, without having to know the exact types involved.
- If you are stuck then consider a different approach or code refactor. Does your code really have to be that dynamic? Does it have to account for any type there is?
- 尽量保持你的代码类型安全。如果编译器不知道类型,则它无法检查您的代码是否正确,并且自动完成之类的功能将不起作用。简单地说:如果您无法在编译时预测类型,那么编译器将如何预测?
- 如果您使用的类实现了一个公共接口,您可以将值转换为该接口。否则考虑创建自己的接口并让类实现该接口。
- 如果您正在使用动态导入的外部库,那么还要检查公共接口。否则考虑创建实现接口的小型包装类。
- 如果您想对对象进行调用,但不关心类型,则将值存储在一个
object
或dynamic
变量中。 - 泛型是创建适用于许多不同类型的可重用代码的好方法,而无需知道所涉及的确切类型。
- 如果您遇到困难,请考虑采用不同的方法或代码重构。你的代码真的必须是动态的吗?它必须考虑任何类型吗?
回答by Mehrdad Afshari
Putting boxing and unboxing aside for simplicity, there's no specific runtime action involved in casting along the inheritance hierarchy. It's mostly a compile time thing. Essentially, a cast tells the compiler to treat the value of the variable as another type.
为简单起见,将装箱和拆箱放在一边,沿继承层次结构转换不涉及特定的运行时操作。这主要是编译时的事情。本质上,强制转换告诉编译器将变量的值视为另一种类型。
What you could do after the cast? You don't know the type, so you wouldn't be able to call any methods on it. There wouldn't be any special thing you could do. Specifically, it can be useful only if you know the possible types at compile time, cast it manually and handle each case separately with if
statements:
选角之后你能做什么?您不知道类型,因此您将无法对其调用任何方法。你不会有什么特别的事情可以做。具体来说,只有在编译时知道可能的类型,手动转换并使用if
语句分别处理每种情况时,它才有用:
if (type == typeof(int)) {
int x = (int)obj;
DoSomethingWithInt(x);
} else if (type == typeof(string)) {
string s = (string)obj;
DoSomethingWithString(s);
} // ...
回答by Daniel Brückner
How could you do that? You need a variable or field of type T where you can store the object after the cast, but how can you have such a variable or field if you know T only at runtime? So, no, it's not possible.
你怎么能做到这一点?您需要一个 T 类型的变量或字段,您可以在其中存储转换后的对象,但是如果您只在运行时知道 T,您怎么能拥有这样的变量或字段?所以,不,这是不可能的。
Type type = GetSomeType();
Object @object = GetSomeObject();
??? xyz = @object.CastTo(type); // How would you declare the variable?
xyz.??? // What methods, properties, or fields are valid here?
回答by user2008563
public bool TryCast<T>(ref T t, object o)
{
if (
o == null
|| !typeof(T).IsAssignableFrom(o.GetType())
)
return false;
t = (T)o;
return true;
}
回答by maulik13
Other answers do not mention "dynamic" type. So to add one more answer, you can use "dynamic" type to store your resulting object without having to cast converted object with a static type.
其他答案没有提到“动态”类型。因此,要再添加一个答案,您可以使用“动态”类型来存储生成的对象,而不必将转换后的对象转换为静态类型。
dynamic changedObj = Convert.ChangeType(obj, typeVar);
changedObj.Method();
Keep in mind that with the use of "dynamic" the compiler is bypassing static type checking which could introduce possible runtime errors if you are not careful.
请记住,使用“动态”编译器会绕过静态类型检查,如果您不小心,这可能会引入可能的运行时错误。
回答by Harm Salomons
even cleaner:
更干净:
public static bool TryCast<T>(ref T t, object o)
{
if (!(o is T))
{
return false;
}
t = (T)o;
return true;
}
回答by balage
Here is my method to cast an object but not to a generic type variable, rather to a System.Type
dynamically:
这是我将对象强制转换为通用类型变量而不是System.Type
动态类型变量的方法:
I create a lambda expression at run-time using System.Linq.Expressions
, of type Func<object, object>
, that unboxes its input, performs the desired type conversion then gives the result boxed. A new one is needed not only for all types that get casted to, but also for the types that get casted (because of the unboxing step). Creating these expressions is highly time consuming, because of the reflection, the compilation and the dynamic method building that is done under the hood. Luckily once created, the expressions can be invoked repeatedly and without high overhead, so I cache each one.
我在运行时使用System.Linq.Expressions
, of type创建了一个 lambda 表达式Func<object, object>
,它对其输入进行拆箱,执行所需的类型转换,然后将结果装箱。不仅需要转换为所有类型的新类型,而且需要转换的类型(因为拆箱步骤)。创建这些表达式非常耗时,因为反射、编译和动态方法构建是在幕后完成的。幸运的是,一旦创建,表达式就可以被重复调用并且没有高开销,所以我缓存了每一个。
private static Func<object, object> MakeCastDelegate(Type from, Type to)
{
var p = Expression.Parameter(typeof(object)); //do not inline
return Expression.Lambda<Func<object, object>>(
Expression.Convert(Expression.ConvertChecked(Expression.Convert(p, from), to), typeof(object)),
p).Compile();
}
private static readonly Dictionary<Tuple<Type, Type>, Func<object, object>> CastCache
= new Dictionary<Tuple<Type, Type>, Func<object, object>>();
public static Func<object, object> GetCastDelegate(Type from, Type to)
{
lock (CastCache)
{
var key = new Tuple<Type, Type>(from, to);
Func<object, object> cast_delegate;
if (!CastCache.TryGetValue(key, out cast_delegate))
{
cast_delegate = MakeCastDelegate(from, to);
CastCache.Add(key, cast_delegate);
}
return cast_delegate;
}
}
public static object Cast(Type t, object o)
{
return GetCastDelegate(o.GetType(), t).Invoke(o);
}
Note that this isn't magic. Casting doesn't occur in code, as it does with the dynamic
keyword, only the underlying data of the object gets converted. At compile-time we are still left to painstakingly figure out exactly what type our object might be, making this solution impractical. I wrote this as a hack to invoke conversion operators defined by arbitrary types, but maybe somebody out there can find a better use case.
请注意,这不是魔术。转换不会发生在代码中,因为它在dynamic
关键字中发生,只有对象的基础数据会被转换。在编译时,我们仍然需要煞费苦心地弄清楚我们的对象可能是什么类型,这使得这个解决方案不切实际。我写这个是为了调用由任意类型定义的转换运算符,但也许有人可以找到更好的用例。
回答by krzyski
When it comes to casting to Enum type:
在转换为 Enum 类型时:
private static Enum GetEnum(Type type, int value)
{
if (type.IsEnum)
if (Enum.IsDefined(type, value))
{
return (Enum)Enum.ToObject(type, value);
}
return null;
}
And you will call it like that:
你会这样称呼它:
var enumValue = GetEnum(typeof(YourEnum), foo);
This was essential for me in case of getting Description attribute value of several enum types by int value:
在通过 int 值获取几种枚举类型的 Description 属性值的情况下,这对我来说是必不可少的:
public enum YourEnum
{
[Description("Desc1")]
Val1,
[Description("Desc2")]
Val2,
Val3,
}
public static string GetDescriptionFromEnum(Enum value, bool inherit)
{
Type type = value.GetType();
System.Reflection.MemberInfo[] memInfo = type.GetMember(value.ToString());
if (memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), inherit);
if (attrs.Length > 0)
return ((DescriptionAttribute)attrs[0]).Description;
}
return value.ToString();
}
and then:
进而:
string description = GetDescriptionFromEnum(GetEnum(typeof(YourEnum), foo));
string description2 = GetDescriptionFromEnum(GetEnum(typeof(YourEnum2), foo2));
string description3 = GetDescriptionFromEnum(GetEnum(typeof(YourEnum3), foo3));
Alternatively (better approach), such casting could look like that:
或者(更好的方法),这种铸造可能看起来像这样:
private static T GetEnum<T>(int v) where T : struct, IConvertible
{
if (typeof(T).IsEnum)
if (Enum.IsDefined(typeof(T), v))
{
return (T)Enum.ToObject(typeof(T), v);
}
throw new ArgumentException(string.Format("{0} is not a valid value of {1}", v, typeof(T).Name));
}
回答by marianop
If you need to cast objects at runtime without knowing destination type, you can use reflection to make a dynamic converter.
如果您需要在不知道目标类型的情况下在运行时转换对象,您可以使用反射来制作动态转换器。
This is a simplified version (without caching generated method):
这是一个简化版本(没有缓存生成的方法):
public static class Tool
{
public static object CastTo<T>(object value) where T : class
{
return value as T;
}
private static readonly MethodInfo CastToInfo = typeof (Tool).GetMethod("CastTo");
public static object DynamicCast(object source, Type targetType)
{
return CastToInfo.MakeGenericMethod(new[] { targetType }).Invoke(null, new[] { source });
}
}
then you can call it:
那么你可以调用它:
var r = Tool.DynamicCast(myinstance, typeof (MyClass));
回答by Curt
After not finding anything to get around "Object must implement IConvertible" exception when using Zyphrax's answer (except for implementing the interface).. I tried something a little bit unconventional and worked for my situation.
在使用 Zyphrax 的答案(实现接口除外)时,没有找到任何可以解决“对象必须实现 IConvertible”异常的方法后。我尝试了一些非常规的方法并针对我的情况工作。
Using the Newtonsoft.Json nuget package...
使用 Newtonsoft.Json nuget 包...
var castedObject = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(myObject), myType);