在C#中,我可以将类型为object的变量转换为类型为T的变量,其中T是在Type变量中定义的吗?
答案 0 :(得分:162)
当然你可以在这里既简单(假设这是一个T型演员)演员阵容,如果方便的话(假设我们可以把它转换为T)转换:
public T CastExamp1<T>(object input) {
return (T) input;
}
public T ConvertExamp1<T>(object input) {
return (T) Convert.ChangeType(input, typeof(T));
}
修改强>
评论中的一些人说这个答案没有回答这个问题。但是行(T) Convert.ChangeType(input, typeof(T))
提供了解决方案。 Convert.ChangeType
方法尝试将任何Object转换为作为第二个参数提供的Type。
例如:
Type intType = typeof(Int32);
object value1 = 1000.1;
// Variable value2 is now an int with a value of 1000
object value2a = Convert.ChangeType(value1, intType);
int value2b = Convert.ChangeType(value1, intType);
// Variable value3 is now an int with a value of 1000
dynamic value3 = Convert.ChangeType(value1, intType);
我已经用泛型编写了答案,因为我想如果你想在没有处理实际类型的情况下将a something
强制转换为a something else
,这很可能是代码嗅觉的标志。使用适当的接口,99.9%的时间不应该是必需的。在反思中可能有一些边缘情况可能有意义,但我建议避免这些情况。
答案 1 :(得分:92)
其他答案没有提及&#34;动态&#34;类型。所以要再添加一个答案,你可以使用&#34; dynamic&#34;用于存储生成的对象的类型,而不必使用静态类型转换转换的对象。
dynamic changedObj = Convert.ChangeType(obj, typeVar);
changedObj.Method();
请记住,使用&#34; dynamic&#34;编译器绕过静态类型检查,如果你不小心,可能会引入可能的运行时错误。
答案 2 :(得分:19)
这是我的方法来转换对象而不是通用类型变量,而不是动态System.Type
:
我在运行时使用类型为System.Linq.Expressions
的{{1}}创建一个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);
}
关键字一样,只会转换对象的基础数据。在编译时,我们仍然需要精心确定我们的对象可能是什么类型,使得这个解决方案不切实际。我把它写成一个hack来调用由任意类型定义的转换操作符,但也许有人可以找到更好的用例。
答案 3 :(得分:7)
为了简单起见,将装箱和拆箱放在一边,在继承层次结构中进行转换时没有涉及特定的运行时操作。这主要是编译时间的事情。从本质上讲,强制转换告诉编译器将变量的值视为另一种类型。
演员表演后你能做些什么?你不知道类型,所以你将无法调用任何方法。你不能做任何特别的事情。具体来说,只有在编译时知道可能的类型,手动编译并使用if
语句单独处理每个案例时,它才有用:
if (type == typeof(int)) {
int x = (int)obj;
DoSomethingWithInt(x);
} else if (type == typeof(string)) {
string s = (string)obj;
DoSomethingWithString(s);
} // ...
答案 4 :(得分:6)
你怎么能这样做?你需要一个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?
答案 5 :(得分:2)
当涉及到枚举类型时:
private static Enum GetEnum(Type type, int value)
{
if (type.IsEnum)
if (Enum.IsDefined(type, value))
{
return (Enum)Enum.ToObject(type, value);
}
return null;
}
您将这样称呼它:
var enumValue = GetEnum(typeof(YourEnum), foo);
对于通过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();
}
然后:
string description = GetDescriptionFromEnum(GetEnum(typeof(YourEnum), foo));
string description2 = GetDescriptionFromEnum(GetEnum(typeof(YourEnum2), foo2));
string description3 = GetDescriptionFromEnum(GetEnum(typeof(YourEnum3), foo3));
或者(更好的方法),这种转换看起来像这样:
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));
}
答案 6 :(得分:0)
在使用Zyphrax的答案时,除了找不到任何解决方法之外,“对象必须实现IConvertible”异常(实现接口除外)。我尝试了一些非常规的方法并针对我的情况进行了工作。
使用Newtonsoft.Json nuget软件包...
var castedObject = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(myObject), myType);
答案 7 :(得分:0)
H,问题在于您没有T。
您只有一个Type变量。
向MS提示,如果您可以执行
之类的操作 TryCast<typeof(MyClass)>
如果能解决我们所有的问题。
答案 8 :(得分:0)
我永远无法理解为什么您需要高达50的声誉才能发表评论,但我只能说@Curt答案正是我一直在寻找的东西,希望其他人也可以。
在我的示例中,我有一个ActionFilterAttribute用来更新json补丁文档的值。我不是补丁文档的T模型,我不得不将其序列化和反序列化为一个普通的JsonPatchDocument,对其进行修改,然后因为我有了类型,所以再次对其进行序列化和反序列化为该类型。
Type originalType = //someType that gets passed in to my constructor.
var objectAsString = JsonConvert.SerializeObject(myObjectWithAGenericType);
var plainPatchDocument = JsonConvert.DeserializeObject<JsonPatchDocument>(objectAsString);
var plainPatchDocumentAsString= JsonConvert.SerializeObject(plainPatchDocument);
var modifiedObjectWithGenericType = JsonConvert.DeserializeObject(plainPatchDocumentAsString, originalType );
答案 9 :(得分:-1)
public bool TryCast<T>(ref T t, object o)
{
if (
o == null
|| !typeof(T).IsAssignableFrom(o.GetType())
)
return false;
t = (T)o;
return true;
}
答案 10 :(得分:-2)
更干净:
public static bool TryCast<T>(ref T t, object o)
{
if (!(o is T))
{
return false;
}
t = (T)o;
return true;
}
答案 11 :(得分:-2)
如果需要在运行时强制转换对象而不知道目标类型,则可以使用反射来创建动态转换器。
这是简化版本(没有缓存生成的方法):
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 });
}
}
然后您可以调用它:
var r = Tool.DynamicCast(myinstance, typeof (MyClass));