IT

런타임시 유형의 기본값

lottoking 2020. 6. 13. 09:36
반응형

런타임시 유형의 기본값 [중복]


주어진 유형에 대해 기본값을 알고 싶습니다.

C #에는 이와 같은 작업을 수행하기위한 default라는 키워드가 있습니다.

object obj = default(Decimal);

하지만 Type 인스턴스 (myType이라고 함)가 있는데 이것을 말하면

object obj = default(myType);

작동하지 않습니다

이 작업을 수행하는 좋은 방법이 있습니까? 거대한 스위치 블록이 작동하지만 좋은 선택은 아니라는 것을 알고 있습니다.


null참조 유형과 new myType()값 유형 (int, float 등의 경우 0에 해당) 에는 실제로 두 가지 가능성이 있습니다. 따라서 실제로 두 가지 경우 만 고려하면됩니다.

object GetDefaultValue(Type t)
{
    if (t.IsValueType)
        return Activator.CreateInstance(t);

    return null;
}

값 유형에는 항상 기본 생성자가 있으므로 Activator.CreateInstance에 대한 호출은 실패하지 않습니다.


System.Type에 확장 메소드로 추가 할 수도 있습니다.

public static class TypeExtensions
{
    public static object GetDefaultValue(this Type t)
    {
        if (t.IsValueType && Nullable.GetUnderlyingType(t) == null)
            return Activator.CreateInstance(t);
        else
            return null;
    }
}

내 시스템 에서이 문제를 해결 한 다음 런타임에 임의 유형의 기본값을 올바르게 결정하는 방법이 있습니다.이 유형은 수천 가지 유형에 대해 테스트되었습니다.

    /// <summary>
    /// [ <c>public static object GetDefault(this 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>
    /// <example>
    /// To use this method in its native, non-extension form, make a call like:
    /// <code>
    ///     object Default = DefaultValue.GetDefault(someType);
    /// </code>
    /// To use this method in its Type-extension form, make a call like:
    /// <code>
    ///     object Default = someType.GetDefault();
    /// </code>
    /// </example>
    /// <seealso cref="GetDefault&lt;T&gt;"/>
    public static object GetDefault(this 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/enum), 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 메서드는 정적 클래스 DefaultValue에서 구현됩니다. 다음과 같은 명령문으로이 메소드를 호출하십시오.

        object Default = DefaultValue.GetDefault(someType);

GetDefault 메서드를 Type의 확장 메서드로 사용하려면 다음과 같이 호출하십시오.

        object Default = someType.GetDefault();

이 두 번째 유형 확장 접근 방식은 호출에서 포함하는 DefaultValue 클래스 한정자를 참조 할 필요가 없기 때문에 더 간단한 클라이언트 코드 구문입니다.

위의 런타임 런타임 형식 인 GetDefault는 기본 C # 'default'키워드와 동일한 의미로 작동하며 동일한 결과를 생성합니다.

일반적인 형식의 GetDefault를 사용하려면 다음 기능에 액세스 할 수 있습니다.

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

A call to the generic form could be something like:

        int? inDefaultVal = DefaultValue.GetDefault<int?>();

Of course, the above generic form of GetDefault is unnecessary for C#, since it works the same as default(T). It is only useful for a .NET language that does not support the 'default' keyword but which supports generic types. In most cases, the generic form is unnecessary.

A useful corollary method is one to determine whether an object contains the default value for its Type. I also rely on the following IsObjectSetToDefault method for that purpose:

    /// <summary>
    /// [ <c>public static bool IsObjectSetToDefault(this Type ObjectType, object ObjectValue)</c> ]
    /// <para></para>
    /// Reports whether a value of type T (or a null reference of type T) contains the default value for that Type
    /// </summary>
    /// <remarks>
    /// Reports whether the object is empty or unitialized for a reference type or nullable value type (i.e. is null) or 
    /// whether the object contains a default value for a non-nullable value type (i.e. int = 0, bool = false, etc.)
    /// <para></para>
    /// NOTE: For non-nullable value types, this method introduces a boxing/unboxing performance penalty.
    /// </remarks>
    /// <param name="ObjectType">Type of the object to test</param>
    /// <param name="ObjectValue">The object value to test, or null for a reference Type or nullable value Type</param>
    /// <returns>
    /// true = The object contains the default value for its Type.
    /// <para></para>
    /// false = The object has been changed from its default value.
    /// </returns>
    public static bool IsObjectSetToDefault(this Type ObjectType, object ObjectValue)
    {
        // If no ObjectType was supplied, attempt to determine from ObjectValue
        if (ObjectType == null)
        {
            // If no ObjectValue was supplied, abort
            if (ObjectValue == null)
            {
                MethodBase currmethod = MethodInfo.GetCurrentMethod();
                string ExceptionMsgPrefix = currmethod.DeclaringType + " {" + currmethod + "} Error:\n\n";
                throw new ArgumentNullException(ExceptionMsgPrefix + "Cannot determine the ObjectType from a null Value");
            }

            // Determine ObjectType from ObjectValue
            ObjectType = ObjectValue.GetType();
        }

        // Get the default value of type ObjectType
        object Default = ObjectType.GetDefault();

        // If a non-null ObjectValue was supplied, compare Value with its default value and return the result
        if (ObjectValue != null)
            return ObjectValue.Equals(Default);

        // Since a null ObjectValue was supplied, report whether its default value is null
        return Default == null;
    }

The above IsObjectSetToDefault method can either be called in its native form or accessed as a Type-class extension.


How about something like...

class Program
{
  static void Main(string[] args)
  {
    PrintDefault(typeof(object));
    PrintDefault(typeof(string));
    PrintDefault(typeof(int));
    PrintDefault(typeof(int?));
  }

  private static void PrintDefault(Type type)
  {
    Console.WriteLine("default({0}) = {1}", type,
      DefaultGenerator.GetDefaultValue(type));
  }
}

public class DefaultGenerator
{
  public static object GetDefaultValue(Type parameter)
  {
    var defaultGeneratorType =
      typeof(DefaultGenerator<>).MakeGenericType(parameter);

    return defaultGeneratorType.InvokeMember(
      "GetDefault", 
      BindingFlags.Static |
      BindingFlags.Public |
      BindingFlags.InvokeMethod,
      null, null, new object[0]);
  }
}

public class DefaultGenerator<T>
{
  public static T GetDefault()
  {
    return default(T);
  }
}

It produces the following output:

default(System.Object) =
default(System.String) =
default(System.Int32) = 0
default(System.Nullable`1[System.Int32]) =

What do you mean by "Default Value"? All reference Types ("class") have null as default value, while all value types will have their default values according to this table.


Here's a function that will return the default value for a nullable type (in other words, it returns 0 for both Decimal and Decimal?):

public static object DefaultValue(Type maybeNullable)
{
    Type underlying = Nullable.GetUnderlyingType(maybeNullable);
    if (underlying != null)
        return Activator.CreateInstance(underlying);
    return Activator.CreateInstance(maybeNullable);
}

참고URL : https://stackoverflow.com/questions/2490244/default-value-of-a-type-at-runtime

반응형