C #에서 객체 유형의 변수를 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) 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, 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);
나는 당신이 캐스팅하려 할 때 매우 가능성이 코드 냄새의 서명 생각 때문에, 제네릭 답을 작성했습니다 a something
에 a something else
실제 유형을 처리하지 않고. 99.9 %의 시간이 필요하지 않은 적절한 인터페이스. 이해가 가까워 질 수있는 몇 가지 중요한 경우가있을 수 있지만 이러한 경우는 피하는 것이 좋습니다.
편집 2 :
몇 가지 추가 팁 :
- 코드를 가능한 한 안전하게 입력하십시오. 컴파일러가 유형을 알지 못하면 코드가 올바른지 여부를 확인할 수 없으며 자동 완성과 같은 기능이 작동하지 않습니다. 간단히 말해서 : 컴파일 타임에 유형을 예측할 수 없다면 컴파일러는 어떻게 할 수 있습니까?
- 작업중인 클래스가 공통 인터페이스 를 구현하는 경우 해당 인터페이스에 값을 캐스트 할 수 있습니다. 그렇지 않으면 자신 만의 인터페이스를 만들고 클래스가 해당 인터페이스를 구현하도록하십시오.
- 동적으로 가져 오는 외부 라이브러리를 사용하는 경우 공통 인터페이스도 확인하십시오. 그렇지 않으면 인터페이스를 구현하는 작은 랩퍼 클래스 작성을 고려하십시오.
- 객체를 호출하고 싶지만 유형에 신경 쓰지 않으려면 값을
object
또는dynamic
변수 에 저장하십시오 . - 제네릭 은 정확한 유형을 알 필요없이 다양한 유형에 적용되는 재사용 가능한 코드를 만드는 좋은 방법입니다.
- 붙어 있다면 다른 접근법이나 코드 리 팩터를 고려하십시오. 코드가 정말로 역동적이어야합니까? 모든 유형을 설명해야합니까?
답변
다른 답변에는 “동적”유형이 언급되어 있지 않습니다. 따라서 하나 이상의 답변을 추가하기 위해 “동적”유형을 사용하여 변환 된 객체를 정적 유형으로 캐스트하지 않고도 결과 객체를 저장할 수 있습니다.
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);