c# settings - Standardwert eines Typs zur Laufzeit




3 Answers

Es gibt wirklich nur zwei Möglichkeiten: null für Referenztypen und new myType() für new myType() was 0 für int, float usw. entspricht). Sie müssen also nur zwei Fälle berücksichtigen:

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

    return null;
}

(Da Werttypen immer einen Standardkonstruktor haben, wird dieser Aufruf an Activator.CreateInstance niemals fehlschlagen).

file location

Für jeden gegebenen Typ möchte ich seinen Standardwert wissen.

In C # gibt es ein Schlüsselwort namens default, um dies zu tun

object obj = default(Decimal);

aber ich habe eine Instanz von Type (myType genannt) und wenn ich das sage,

object obj = default(myType);

es funktioniert nicht

Gibt es eine gute Möglichkeit, dies zu tun? Ich weiß, dass ein großer Schalterblock funktionieren wird, aber das ist keine gute Wahl.




Nachdem ich dieses Problem in meinen eigenen Systemen gelöst habe, gibt es hier eine Methode, um den Standardwert eines beliebigen Typs zur Laufzeit, der gegen Tausende von Typen getestet wurde, korrekt zu bestimmen:

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

In diesen Beispielen wird die GetDefault-Methode in der statischen Klasse DefaultValue implementiert. Rufen Sie diese Methode mit einer Anweisung wie folgt auf:

        object Default = DefaultValue.GetDefault(someType);

Um die GetDefault-Methode als eine Erweiterungsmethode für Type zu verwenden, rufen Sie sie wie folgt auf:

        object Default = someType.GetDefault();

Dieser zweite Typ-Erweiterungs-Ansatz ist eine einfachere Client-Code-Syntax, da es nicht mehr erforderlich ist, auf das enthaltene DefaultValue-Klassen-Qualifikationsmerkmal für den Aufruf zu verweisen.

Die obige Laufzeitform von GetDefault funktioniert mit identischer Semantik wie das primitive Schlüsselwort C # 'default' und erzeugt die gleichen Ergebnisse.

Um eine generische Form von GetDefault zu verwenden, können Sie auf die folgende Funktion zugreifen:

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

Ein Aufruf der generischen Form könnte etwa lauten:

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

Natürlich ist die obige generische Form von GetDefault für C # nicht notwendig, da sie genauso funktioniert wie der Standard (T). Es ist nur für eine .NET-Sprache nützlich, die das Schlüsselwort 'default' nicht unterstützt, aber generische Typen unterstützt. In den meisten Fällen ist die generische Form unnötig.

Eine nützliche logische Methode ist eine, um festzustellen, ob ein Objekt den Standardwert für seinen Typ enthält. Ich verlasse mich zu diesem Zweck auch auf die folgende IsObjectSetToDefault-Methode:

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

Die obige IsObjectSetToDefault Methode kann entweder in ihrer nativen Form aufgerufen oder als Type-class-Erweiterung aufgerufen werden.




Was meinst du mit "Standardwert"? Alle Referenztypen ("Klasse") haben als Standardwert null, während alle Werttypen ihre Standardwerte gemäß dieser Tabelle haben .




Related

c# types default