developer tip

.NET-반영된 PropertyInfo의 기본값 가져 오기

copycodes 2020. 12. 27. 11:18
반응형

.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&lt; T &gt;()</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&lt;T&gt;"/>
    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

반응형