.NET-반영된 PropertyInfo의 기본값 가져 오기
이것은 오늘 나를 정말 힘들게합니다. 그다지 어렵지는 않지만 System.Reflection.PropertyInfo 개체가 있습니다. 데이터베이스 조회 결과를 기반으로 값을 설정하고 싶습니다 (ORM, 열을 속성에 다시 매핑).
내 문제는 DB 반환 값이 DBNull이면 속성 값을 기본값으로 설정하고 싶습니다.
value = default(T); // where T is the type of the property.
그러나 내가 가지고있는 Type을 주면 default () 메서드가 컴파일되지 않습니다.
object myObj = ???; // doesn't really matter. some arbitrary class.
PropertyInfo myPropInf = ???; // the reflection data for a property on the myObj object.
myPropInf.SetValue(myObj, default(myPropInf.PropertyType), null);
위의 내용은 컴파일되지 않습니다. default (Type)이 잘못되었습니다. 나는 또한 다음과 같이 생각했다.
object myObj = ???;
PropertyInfo myPropInf = ???;
myPropInf.SetValue(myObj, Activator.CreateInstance(myPropInf.PropertyType), null);
그러나 Type이 문자열이면 "new String ()"값을 할당하지만 "default (string)"이 반환하는 "null"을 원합니다.
그래서 내가 여기서 무엇을 놓치고 있습니까? 정말 해키 한 방법은 myObj의 Type의 새 인스턴스를 만들고 속성을 복사하는 것이라고 생각하지만 어리석은 것처럼 보입니다 ...
object myObj = ???;
PropertyInfo myPropInf = ???;
var blank = Activator.CreateInstance(myObj.GetType());
object defaultValue = myPropInf.GetValue(blank, null);
myPropInf.SetValue(myObj, defaultValue, null);
나는 완전히 새로운 인스턴스를 만들기 위해 메모리를 낭비하지 않고 속성에 대한 기본값을 얻습니다. 매우 낭비적인 것 같습니다.
어떤 아이디어?
당신이 그렇게한다면
prop.SetValue(obj,null,null);
값 유형이면 기본값으로 설정하고 참조 유형이면 null로 설정합니다.
object defaultValue = type.IsValueType ? Activator.CreateInstance(type) : null;
"null"트릭은 유형에 대해 0 값으로 설정합니다 . 이는 속성의 기본값과 같을 필요는 없습니다. 첫째, 새로운 물건이라면 그냥 그대로 두는 게 어떨까요? 또는 다음을 사용하십시오 TypeDescriptor
.
PropertyDescriptor prop = TypeDescriptor.GetProperties(foo)["Bar"];
if (prop.CanResetValue(foo)) prop.ResetValue(foo);
이는 [DefaultValue]
및 Reset{name}()
패턴 (바인딩 및 직렬화에 사용됨)을 모두 존중 하므로 매우 다양하고 재사용이 가능합니다.
이 작업을 많이 수행하는 경우 HyperDescriptorTypeDescriptor
를 재사용 PropertyDescriptorCollection
하고 사용 하여 리플렉션 대신 사용하여 성능을 높일 수도 있습니다 (동일한 코드이지만 refletion 또는 raw보다 훨씬 빠름 ).TypeDescriptor
수천 가지 유형에 대해 작성하고 테스트 한 다음 방법을 시도해보십시오.
/// <summary>
/// [ <c>public static T GetDefault< T >()</c> ]
/// <para></para>
/// Retrieves the default value for a given Type
/// </summary>
/// <typeparam name="T">The Type for which to get the default value</typeparam>
/// <returns>The default value for Type T</returns>
/// <remarks>
/// If a reference Type or a System.Void Type is supplied, this method always returns null. If a value type
/// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an
/// exception.
/// </remarks>
/// <seealso cref="GetDefault(Type)"/>
public static T GetDefault<T>()
{
return (T) GetDefault(typeof(T));
}
/// <summary>
/// [ <c>public static object GetDefault(Type type)</c> ]
/// <para></para>
/// Retrieves the default value for a given Type
/// </summary>
/// <param name="type">The Type for which to get the default value</param>
/// <returns>The default value for <paramref name="type"/></returns>
/// <remarks>
/// If a null Type, a reference Type, or a System.Void Type is supplied, this method always returns null. If a value type
/// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an
/// exception.
/// </remarks>
/// <seealso cref="GetDefault<T>"/>
public static object GetDefault(Type type)
{
// If no Type was supplied, if the Type was a reference type, or if the Type was a System.Void, return null
if (type == null || !type.IsValueType || type == typeof(void))
return null;
// If the supplied Type has generic parameters, its default value cannot be determined
if (type.ContainsGenericParameters)
throw new ArgumentException(
"{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type +
"> contains generic parameters, so the default value cannot be retrieved");
// If the Type is a primitive type, or if it is another publicly-visible value type (i.e. struct), return a
// default instance of the value type
if (type.IsPrimitive || !type.IsNotPublic)
{
try
{
return Activator.CreateInstance(type);
}
catch (Exception e)
{
throw new ArgumentException(
"{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe Activator.CreateInstance method could not " +
"create a default instance of the supplied value type <" + type +
"> (Inner Exception message: \"" + e.Message + "\")", e);
}
}
// Fail with exception
throw new ArgumentException("{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type +
"> is not a publicly-visible type, so the default value cannot be retrieved");
}
GetDefault의 첫 번째 (일반) 버전은 물론 default (T) 키워드 만 사용할 수 있으므로 C #에 대해 중복됩니다.
즐겨!
이것은 불필요한 사용자 지정 코드를 추가하지 않고도 .NET 런타임의 기능을 유지하는보다 세련된 버전입니다.
참고 : .NET 3.5 SP1 용으로 작성된이 코드
namespace System {
public static class TypedDefaultExtensions {
public static object ToDefault(this Type targetType) {
if (targetType == null)
throw new NullReferenceException();
var mi = typeof(TypedDefaultExtensions)
.GetMethod("_ToDefaultHelper", Reflection.BindingFlags.Static | Reflection.BindingFlags.NonPublic);
var generic = mi.MakeGenericMethod(targetType);
var returnValue = generic.Invoke(null, new object[0]);
return returnValue;
}
static T _ToDefaultHelper<T>() {
return default(T);
}
}
}
용법:
PropertyInfo pi; // set to some property info
object defaultValue = pi.PropertyType.ToDefault();
public struct MyTypeValue { public int SomeIntProperty { get; set; }
var reflectedType = typeof(MyTypeValue);
object defaultValue2 = reflectedType.ToDefault();
Rashad Rivera (OmegusPrime.com)
I know this is an old post, but I like this twist on Darin Dimitrov's answer. It first checks for any DefualtValue attributes then uses Darin Dimitrov's answer:
public static object GetDefaultValueForProperty(this PropertyInfo property)
{
var defaultAttr = property.GetCustomAttribute(typeof(DefaultValueAttribute));
if (defaultAttr != null)
return (defaultAttr as DefaultValueAttribute).Value;
var propertyType = property.PropertyType;
return propertyType.IsValueType ? Activator.CreateInstance(propertyType) : null;
}
ReferenceURL : https://stackoverflow.com/questions/407337/net-get-default-value-for-a-reflected-propertyinfo
'developer tip' 카테고리의 다른 글
Celery AttributeError : 비동기 오류 (0) | 2020.12.27 |
---|---|
C #에서 'String.Contains ( "term")'을 나타내는 식 트리를 만들려면 어떻게해야합니까? (0) | 2020.12.27 |
C #에서 쿼리 문자열을 사전으로 변환하는 가장 좋은 방법 (0) | 2020.12.27 |
목록의 이동 평균 계산 (0) | 2020.12.27 |
Android : SlidingDrawer의 높이를 wrap_content로 설정할 수 있습니까? (0) | 2020.12.27 |