私はリフレクションを使ってType
のプロパティをループし、特定の型をデフォルトに設定します。今、私はタイプを切り替えて明示的にdefault(Type)
を設定することができますが、私はむしろ1行でそれをしたいです。デフォルトと同等のプログラムによるものはありますか?
public static object GetDefault(Type type)
{
if(type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
.net標準などの新しいバージョンの.netでは、type.IsValueType
はtype.GetTypeInfo().IsValueType
と書く必要があります。
リフレクションを指定して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);
}
PropertyInfo.SetValue(obj, null)
を使うことができます。値型で呼び出された場合はデフォルトが与えられます。この動作は .NET 4.0では そして .NET 4.5では で文書化されています。
.NET 4.0以降を使用していて、コード外で定義された規則の体系化ではないプログラムバージョンが必要な場合は、 Expression
を作成してコンパイルして実行できます。 - 飛ぶ。
次の拡張メソッドは Type
を取り、 default(T)
からDefault
クラスの Expression
メソッド から返される値を取得します。
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
インスタンスに対して呼び出していて、常に使用していない場合は、キャッシュによって消費されるメモリがメリットを上回る可能性があります。
なぜジェネリック医薬品は外に出ていると言うのですか?
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);
}
これはFlemのソリューションを最適化したものです。
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;
}
}
}
選ばれた答えは良い答えですが、返されたオブジェクトには注意してください。
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.");
式はここで役立ちます:
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つの考えを持っています:あなたが設定したいプロパティのタイプを知っていれば、あなたはあなた自身のdefault(T)
を書くことができます。 2つのケースがあります - T
は値型、T
は参照型です。あなたはT.IsValueType
をチェックすることによってこれを見ることができます。 T
が参照型の場合は、単純にnull
に設定できます。 T
が値型の場合、デフォルトのパラメータなしのコンストラクタが使用され、これを呼び出して「空白」の値を取得できます。
私はこのように同じ仕事をします。
//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;
}
Drorの答えと同じですが、拡張方法としては:
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;
}
}
}
@ 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));
}
/// <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;
}