Programing

Type 변수를 사용하여 변수 캐스팅

lottogame 2020. 4. 7. 08:16
반응형

Type 변수를 사용하여 변수 캐스팅


C #에서 object 유형의 변수를 T 유형의 변수로 캐스트 할 수 있습니까? T는 Type 변수에 정의되어 있습니까?


여기서 당신이 할 수있는 것은 간단한 (이것이 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메소드는 모든 오브젝트를 두 번째 인수로 제공된 유형으로 변환하려고 시도합니다.

예를 들면 다음과 같습니다.

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 somethinga something else실제 유형을 처리하지 않고. 99.9 %의 시간이 필요하지 않은 적절한 인터페이스. 이해가 가까워 질 수있는 몇 가지 중요한 경우가있을 수 있지만 이러한 경우는 피하는 것이 좋습니다.


다른 답변에는 "동적"유형이 언급되어 있지 않습니다. 따라서 하나 이상의 답변을 추가하기 위해 "동적"유형을 사용하여 변환 된 객체를 정적 유형으로 캐스트하지 않고도 결과 객체를 저장할 수 있습니다.

dynamic changedObj = Convert.ChangeType(obj, typeVar);
changedObj.Method();

"동적"을 사용하면 컴파일러는 정적 유형 검사를 무시하므로주의하지 않으면 런타임 오류가 발생할 수 있습니다.


다음은 객체를 캐스팅하지만 일반 유형 변수가 아닌 System.Type동적으로 캐스팅하는 방법입니다 .

System.Linq.Expressions, type을 사용하여 런타임에 람다 식을 작성하여 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);
}

이것은 마술이 아닙니다. dynamic키워드에서 와 마찬가지로 코드에서는 캐스팅이 발생하지 않으며 객체의 기본 데이터 만 변환됩니다. 컴파일 타임에 우리는 여전히 객체의 유형이 무엇인지 정확하게 파악 하여이 솔루션을 비실용적으로 만듭니다. 나는 이것을 임의의 유형으로 정의 된 변환 연산자를 호출하는 핵으로 썼다. 그러나 아마도 누군가 더 나은 사용 사례를 찾을 수있을 것이다.


단순함을 위해 박싱과 언 박싱을 제쳐두고 상속 계층 구조를 따라 캐스팅하는 것과 관련된 특정 런타임 작업은 없습니다. 대부분 컴파일 타임 일입니다. 기본적으로 캐스트는 변수 값을 다른 유형으로 처리하도록 컴파일러에 지시합니다.

캐스트 후 무엇을 할 수 있습니까? 타입을 모르기 때문에 어떤 메소드도 호출 할 수 없습니다. 당신이 할 수있는 특별한 일은 없을 것입니다. 특히 컴파일 타임에 가능한 유형을 알고 수동으로 캐스트하고 if명령문을 사용 하여 각 케이스를 개별적으로 처리하는 경우에만 유용 합니다.

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?

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

이것은 여러 enum 유형의 Description 속성 값을 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));
    }

Zyphrax의 답변을 사용할 때 "인터페이스는 IConvertible을 구현해야 함"예외를 피할 수없는 것을 발견 한 후 (인터페이스 구현 제외). 나는 약간의 비 전통적인 것을 시도하고 내 상황에서 일했습니다.

Newtonsoft.Json nuget 패키지 사용 ...

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

public bool TryCast<T>(ref T t, object o)
{
    if (
        o == null
        || !typeof(T).IsAssignableFrom(o.GetType())
        )
        return false;
    t = (T)o;
    return true;
}

더 깨끗하게 :

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

        t = (T)o;
        return true;
    }

대상 유형을 몰라도 런타임에 객체를 캐스트해야하는 경우 리플렉션을 사용하여 동적 변환기를 만들 수 있습니다.

이것은 캐싱 생성 방법없이 단순화 된 버전입니다.

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

참고 URL : https://stackoverflow.com/questions/972636/casting-a-variable-using-a-type-variable

반응형