在c#中,我可以将类型对象的变量转换为类型T的变量,其中T在类型变量中定义?
为了简单起见,将装箱和解装箱放在一边,沿着继承层次结构进行强制转换时不涉及特定的运行时操作。这主要是编译时的事情。本质上,强制转换告诉编译器将变量的值视为另一种类型。
试镜之后你能做什么?你不知道它的类型,所以你不能对它调用任何方法。你不会有什么特别的事情可以做。具体来说,只有当你在编译时知道可能的类型,手动转换它并使用if语句分别处理每个case时,它才有用:
if (type == typeof(int)) {
int x = (int)obj;
DoSomethingWithInt(x);
} else if (type == typeof(string)) {
string s = (string)obj;
DoSomethingWithString(s);
} // ...
你怎么能这么做?您需要一个类型为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?
下面是一个类型转换和转换的例子:
using System;
public T CastObject<T>(object input) {
return (T) input;
}
public T ConvertObject<T>(object input) {
return (T) Convert.ChangeType(input, typeof(T));
}
编辑:
评论里有人说这个答案没有回答问题。但是T转换。ChangeType(input, typeof(T))提供了解决方案。转换。方法尝试将任何对象转换为作为第二个参数提供的类型。
例如:
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);
我用泛型写了答案,因为我认为,当您想要将一个类型转换为另一个类型而不处理实际类型时,这很可能是代码气味的标志。在99.9%的情况下,不需要使用合适的界面。当涉及到反射时,可能有一些边缘情况是有意义的,但我建议避免这些情况。
编辑2:
一些额外的建议:
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 or dynamic variable. Generics can 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?
public bool TryCast<T>(ref T t, object o)
{
if (
o == null
|| !typeof(T).IsAssignableFrom(o.GetType())
)
return false;
t = (T)o;
return true;
}
其他答案没有提到“动态”类型。因此,要再添加一个答案,您可以使用“动态”类型来存储结果对象,而不必使用静态类型强制转换转换后的对象。
dynamic changedObj = Convert.ChangeType(obj, typeVar);
changedObj.Method();
请记住,使用“动态”,编译器会绕过静态类型检查,如果你不小心,可能会引入运行时错误。
此外,还假定obj是typeVar类型的实例,或者可以转换为该类型。
甚至清洁:
public static bool TryCast<T>(ref T t, object o)
{
if (!(o is T))
{
return false;
}
t = (T)o;
return true;
}
下面是我的方法来强制转换一个对象,但不是泛型类型变量,而是一个系统。动态类型:
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.
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);
}
请注意,这不是魔术。与dynamic关键字不同,强制转换不会在代码中发生,只会转换对象的底层数据。在编译时,我们仍然需要费力地找出我们的对象可能是什么类型,这使得这个解决方案不切实际。我写这篇文章是为了调用由任意类型定义的转换操作符,但也许有人能找到更好的用例。
当谈到转换为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;
}
你可以这样称呼它:
var enumValue = GetEnum(typeof(YourEnum), foo);
这对我来说是必要的情况下,获得几个枚举类型的描述属性值的int值:
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));
}
如果需要在不知道目标类型的情况下在运行时强制转换对象,可以使用反射来生成动态转换器。
这是一个简化版本(没有缓存生成的方法):
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));
当使用Zyphrax的答案时,没有找到任何东西来绕过“对象必须实现IConvertible”异常(实现接口除外)..我尝试了一些非常规的方法,但在我的情况下奏效了。
使用Newtonsoft。Json nuget包…
var castedObject = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(myObject), myType);
我永远不会理解为什么你需要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 );
推荐文章
- .NET中的Map和Reduce
- 我如何能使一个组合框不可编辑的。net ?
- .NET反射的成本有多高?
- 实体框架回滚并移除不良迁移
- 将流转换为字符串并返回
- 熊猫能自动从CSV文件中读取日期吗?
- 在c#中检查字符串是否只包含数字的最快方法
- IEquatable和重写Object.Equals()之间的区别是什么?
- 如何在TypeScript中声明一个固定长度的数组
- 创建一个堆栈大小为默认值50倍的线程有什么危险?
- 转换JSON字符串到JSON对象c#
- 显示两个datetime值之间的小时差值
- 如何设置enum为空
- 选择Enum类型的默认值而无需更改值
- 我如何设置在一个组合框中选择的项目,以匹配我的字符串使用c# ?