プログラム的にdefault(Type)と同等


514

リフレクションを使用してTypeのプロパティをループし、特定のタイプをデフォルトに設定しています。これで、タイプを切り替えてdefault(Type)明示的に設定することができましたが、1行で行いたいと思います。プログラム的にデフォルトに相当するものはありますか?


これは機能するはずです:Nullable <T> a = new Nullable <T>()。GetValueOrDefault();
ダンサー42

回答:


694
  • 値型の場合は、Activator.CreateInstanceを使用してください。
  • 参照型を使用する場合はnullを返すだけ
public static object GetDefault(Type type)
{
   if(type.IsValueType)
   {
      return Activator.CreateInstance(type);
   }
   return null;
}

.net標準などの.netの新しいバージョンでtype.IsValueTypeは、次のように記述する必要があります。type.GetTypeInfo().IsValueType


22
これはボックス化された値の型を返すため、default(Type)と完全に同等ではありません。ただし、ジェネリックなしで取得するのと同じくらいの距離です。
ラッセルギディングス

8
だから何?引数がある型が見つかった場合default(T) != (T)(object)default(T) && !(default(T) != default(T))、同等であるため、それがボックス化されているかどうかは関係ありません。
ミゲルアンジェロ

7
述語の最後の部分は、オペレーターのオーバーロードによる不正行為を回避するdefault(T) != default(T)ことです... false を返す可能性があり、それは不正行為です!=)
ミゲルアンジェロ

4
これは私をたくさん助けたが、私はこの質問を検索する一部の人に役に立つかもしれない一つのことを追加する必要がありますと思った-そこにあなたが望んでいた場合は同等の方法もあります配列指定された型のを、あなたが使用してそれを得ることができますArray.CreateInstance(type, length)
Darrel Hoffman 2013

4
不明な値タイプのインスタンスを作成することについて心配しませんか?これは付随的な影響を与える可能性があります。
ygormutti 2013年

103

リフレクションを使用してdefault(T)を返すメソッドを呼び出さないのはなぜですか?以下を使用して、任意のタイプのGetDefaultを使用できます。

    public object GetDefault(Type t)
    {
        return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null);
    }

    public T GetDefaultGeneric<T>()
    {
        return default(T);
    }

7
とてもシンプルなのでこれは素晴らしいです。これは最善の解決策ではありませんが、この手法は多くの同様の状況で役立つため、覚えておくべき重要な解決策です。
コンフィギュレー

代わりにジェネリックメソッド「GetDefault」を呼び出す(オーバーロード)場合は、次のようにします。this.GetType()。GetMethod( "GetDefault"、new Type [0])。<AS_IS>
Stefan Steiger

2
この実装は、受け入れられた回答よりも(反映のため)非常に遅いことに注意してください。それでも実行可能ですが、パフォーマンスを向上させるには、GetMethod()/ MakeGenericMethod()呼び出しのキャッシュをセットアップする必要があります。
Doug

1
type引数が無効である可能性があります。たとえば、voidメソッドのMethodBase.ResultType()は、名前が「Void」またはFullNameが「System.Void」のTypeオブジェクトを返します。したがって、私はガードを置きます:if(t.FullName == "System.Void")がnullを返します。解決策をありがとう。
Valo

8
nameof(GetDefaultGeneric)代わりにできる限り使用する"GetDefaultGeneric"
Mugen

87

使用できますPropertyInfo.SetValue(obj, null)。値タイプで呼び出された場合、デフォルトが与えられます。この動作は、.NET 4.0および.NET 4.5で文書化されています


7
この特定の質問-タイプのプロパティをループし、それらを「デフォルト」に設定する-これは見事に機能します。リフレクションを使用してSqlDataReaderからオブジェクトに変換するときに使用します。
アルノピーターズ

57

.NET 4.0以降を使用していて、コードの外部で定義されたルールの体系化されていないプログラムバージョンが必要な場合は、を作成Expression、コンパイルして、その場で実行できます。

次の拡張メソッドはa Typeを受け取り、クラスのメソッドdefault(T)介して返された値を取得します。DefaultExpression

public static T GetDefaultValue<T>()
{
    // We want an Func<T> which returns the default.
    // Create that expression here.
    Expression<Func<T>> e = Expression.Lambda<Func<T>>(
        // The default value, always get what the *code* tells us.
        Expression.Default(typeof(T))
    );

    // Compile and return the value.
    return e.Compile()();
}

public static object GetDefaultValue(this Type type)
{
    // Validate parameters.
    if (type == null) throw new ArgumentNullException("type");

    // We want an Func<object> which returns the default.
    // Create that expression here.
    Expression<Func<object>> e = Expression.Lambda<Func<object>>(
        // Have to convert to object.
        Expression.Convert(
            // The default value, always get what the *code* tells us.
            Expression.Default(type), typeof(object)
        )
    );

    // Compile and return the value.
    return e.Compile()();
}

また、上記の値をに基づいてキャッシュする必要Typeがありますが、これを多数のTypeインスタンスに対して呼び出す場合は、常に使用しないでください。キャッシュによって消費されるメモリがメリットを上回る可能性があります。


4
'return type.IsValueType?Activator.CreateInstance(type):null; ' e.Compile()();よりも1000倍高速です。
Cyrus 14

1
@Cyrusキャッシュすれば、逆になると確信していますe.Compile()。それが表現のポイントです。
nawfal

2
ベンチマークを実行しました。明らかに、結果はe.Compile()キャッシュされるべきですが、と仮定すると、このメソッドは、例えばの場合、およそ14倍高速ですlong。ベンチマークと結果については、gist.github.com / pvginkel / fed5c8512b9dfefc2870c6853bbfbf8bをご覧ください。
Pieter van

3
興味がないe.Compile()のに、なぜキャッシュではなくe.Compile()()ですか?つまり、型のデフォルト型は実行時に変更できますか?そうでない場合(私はそうだと思います)、コンパイルされた式ではなく、結果をキャッシュに格納するだけで、パフォーマンスがさらに向上します。
JohnLBevan 2018年

3
@JohnLBevan-はい、そうすれば、結果を取得するためにどの手法を使用するかは問題になりません-すべての償却パフォーマンスが非常に高速になります(辞書検索)。
Daniel Earwicker

38

ジェネリック医薬品が視野に入らないのはなぜですか?

    public static object GetDefault(Type t)
    {
        Func<object> f = GetDefault<object>;
        return f.Method.GetGenericMethodDefinition().MakeGenericMethod(t).Invoke(null, null);
    }

    private static T GetDefault<T>()
    {
        return default(T);
    }

シンボルメソッドを解決できません。PCL for Windowsを使用します。
・クール

1
ジェネリックメソッドを実行時に作成し、それを数千回続けて使用するのはどれくらい費用がかかりますか。
C. Tewalt 2014

1
このようなことを考えていました。私にとって最高で最もエレガントなソリューション。Compact Framework 2.0でも機能します。パフォーマンスが心配な場合は、いつでもジェネリックメソッドをキャッシュできますよね。
2015年

このソリューションはぴったりです!ありがとう!
Lachezar Lalov、2018年

25

これは、最適化されたフレムのソリューションです。

using System.Collections.Concurrent;

namespace System
{
    public static class TypeExtension
    {
        //a thread-safe way to hold default instances created at run-time
        private static ConcurrentDictionary<Type, object> typeDefaults =
           new ConcurrentDictionary<Type, object>();

        public static object GetDefaultValue(this Type type)
        {
            return type.IsValueType
               ? typeDefaults.GetOrAdd(type, Activator.CreateInstance)
               : null;
        }
    }
}

2
リターンの短縮版:return type.IsValueType ? typeDefaults.GetOrAdd(type, Activator.CreateInstance) : null;
マークホイットフェルド2013年

3
可変構造体はどうですか?ボックス化された構造体のフィールドを変更してデータを変更することが可能(かつ合法)であることを知っていますか?
IllidanS4はモニカを2015

メソッドの名前としての@ IllidanS4は、これがデフォルトのValueTypeの値に対してのみであることを意味します。
aderesh

8

選ばれた答えは良い答えですが、返されるオブジェクトに注意してください。

string test = null;
string test2 = "";
if (test is string)
     Console.WriteLine("This will never be hit.");
if (test2 is string)
     Console.WriteLine("Always hit.");

外挿しています...

string test = GetDefault(typeof(string));
if (test is string)
     Console.WriteLine("This will never be hit.");

14
true、しかしそれはdefault(string)と他のすべての参照タイプにも
当てはまり

stringは奇妙な鳥です-nullを返すこともできる値型です。コードがstring.emptyを返すようにしたい場合は、特別なケースを追加してください
Dror Helper

15
@Dror-文字列は不変の参照型であり、値型ではありません。
ljs

@kronozそうです-必要に応じてstring.emptyまたはnullを返すことで文字列を処理できることを意味しました。
Dror Helper、

5

式はここで役立ちます:

    private static Dictionary<Type, Delegate> lambdasMap = new Dictionary<Type, Delegate>();

    private object GetTypedNull(Type type)
    {
        Delegate func;
        if (!lambdasMap.TryGetValue(type, out func))
        {
            var body = Expression.Default(type);
            var lambda = Expression.Lambda(body);
            func = lambda.Compile();
            lambdasMap[type] = func;
        }
        return func.DynamicInvoke();
    }

私はこのスニペットをテストしませんでしたが、参照型の「型付き」nullを生成する必要があると思います。


1
"typed" nulls-説明してください。どのオブジェクトを返しますか?タイプのオブジェクトを返し、typeその値がnullである場合、そのオブジェクトはそれ以外の情報を持つことはできませんnullnull値をクエリして、その型が何であるかを調べることはできません。nullを返さないが..を返す場合..わからない場合は、のようには動作しませんnull
ToolmakerSteve 2018

3

シンプルでエレガントなものはまだ見つかりませんが、1つ考えますdefault(T)。設定するプロパティのタイプがわかっている場合は、独自のを作成できます。T値タイプとT参照タイプの2つのケースがあります。これを確認すると、これを確認できますT.IsValueTypeTが参照型の場合は、単純にに設定できますnullTが値型の場合、「空白」の値を取得するために呼び出すことができるデフォルトのパラメーターなしコンストラクターがあります。


3

私はこのように同じ仕事をします。

//in MessageHeader 
   private void SetValuesDefault()
   {
        MessageHeader header = this;             
        Framework.ObjectPropertyHelper.SetPropertiesToDefault<MessageHeader>(this);
   }

//in ObjectPropertyHelper
   public static void SetPropertiesToDefault<T>(T obj) 
   {
            Type objectType = typeof(T);

            System.Reflection.PropertyInfo [] props = objectType.GetProperties();

            foreach (System.Reflection.PropertyInfo property in props)
            {
                if (property.CanWrite)
                {
                    string propertyName = property.Name;
                    Type propertyType = property.PropertyType;

                    object value = TypeHelper.DefaultForType(propertyType);
                    property.SetValue(obj, value, null);
                }
            }
    }

//in TypeHelper
    public static object DefaultForType(Type targetType)
    {
        return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
    }

2

ドロールの答えと同等ですが、拡張メソッドとして:

namespace System
{
    public static class TypeExtensions
    {
        public static object Default(this Type type)
        {
            object output = null;

            if (type.IsValueType)
            {
                output = Activator.CreateInstance(type);
            }

            return output;
        }
    }
}

2

@Rob Fonseca-Ensorのソリューションに対するわずかな調整:GetMethodではなくGetRuntimeMethodを使用しているため、次の拡張メソッドも.Net Standardで機能します。

public static class TypeExtensions
{
    public static object GetDefault(this Type t)
    {
        var defaultValue = typeof(TypeExtensions)
            .GetRuntimeMethod(nameof(GetDefaultGeneric), new Type[] { })
            .MakeGenericMethod(t).Invoke(null, null);
        return defaultValue;
    }

    public static T GetDefaultGeneric<T>()
    {
        return default(T);
    }
}

...そして品質を気にする人のための対応する単体テスト:

[Fact]
public void GetDefaultTest()
{
    // Arrange
    var type = typeof(DateTime);

    // Act
    var defaultValue = type.GetDefault();

    // Assert
    defaultValue.Should().Be(default(DateTime));
}

0
 /// <summary>
    /// returns the default value of a specified type
    /// </summary>
    /// <param name="type"></param>
    public static object GetDefault(this Type type)
    {
        return type.IsValueType ? (!type.IsGenericType ? Activator.CreateInstance(type) : type.GenericTypeArguments[0].GetDefault() ) : null;
    }

2
Nullable<T>型に対しては機能しません。default(Nullable<T>)これは、に相当するものを返しませんnull。Drorが認めた回答はより効果的に機能します。
・クール

リフレクションを使用してnull可能かどうかを確認できます...
dancer42

0

これはうまくいくはずです: Nullable<T> a = new Nullable<T>().GetValueOrDefault();

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.