在c#中,我可以将类型对象的变量转换为类型T的变量,其中T在类型变量中定义?


当前回答

下面是一个类型转换和转换的例子:

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?

其他回答

下面是我的方法来强制转换一个对象,但不是泛型类型变量,而是一个系统。动态类型:

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关键字不同,强制转换不会在代码中发生,只会转换对象的底层数据。在编译时,我们仍然需要费力地找出我们的对象可能是什么类型,这使得这个解决方案不切实际。我写这篇文章是为了调用由任意类型定义的转换操作符,但也许有人能找到更好的用例。

甚至清洁:

    public static bool TryCast<T>(ref T t, object o)
    {
        if (!(o is T))
        {
            return false;
        }

        t = (T)o;
        return true;
    }

当使用Zyphrax的答案时,没有找到任何东西来绕过“对象必须实现IConvertible”异常(实现接口除外)..我尝试了一些非常规的方法,但在我的情况下奏效了。

使用Newtonsoft。Json nuget包…

var castedObject = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(myObject), myType);

如果需要在不知道目标类型的情况下在运行时强制转换对象,可以使用反射来生成动态转换器。

这是一个简化版本(没有缓存生成的方法):

    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));

当谈到转换为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));
    }