tag*_*s2k 492 c# reflection default
我正在使用反射来遍历一个Type
属性并将某些类型设置为默认值.现在,我可以对类型进行切换并default(Type)
明确设置,但我宁愿在一行中进行.有默认的程序化等价物吗?
Dro*_*per 667
public static object GetDefault(Type type)
{
if(type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
在较新版本的.net中,例如.net标准,type.IsValueType
需要写成type.GetTypeInfo().IsValueType
dra*_*707 99
为什么不用反射调用返回默认值(T)的方法?您可以使用任何类型的GetDefault:
public object GetDefault(Type t)
{
return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null);
}
public T GetDefaultGeneric<T>()
{
return default(T);
}
Run Code Online (Sandbox Code Playgroud)
cas*_*One 54
如果您使用的是.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()();
}
Run Code Online (Sandbox Code Playgroud)
您还应该根据它缓存上述值Type
,但要注意,如果您为大量Type
实例调用此值,并且不要经常使用它,则缓存所消耗的内存可能会超过收益.
Rob*_*sor 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);
}
Run Code Online (Sandbox Code Playgroud)
小智 24
这是优化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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Tin*_*ter 10
这里有几个答案使用Activator.CreateInstance
. 然而,自从做出了这些答案后,C# 和 .NET 进行了更改,允许用户使用无参数构造函数定义结构(文档链接)。 Activator.CreateInstance
如果定义了,将执行这样的无参数构造函数,并且您将不再获得默认实例。
相反,您可以使用RuntimeHelpers.GetUninitializedObject
,如下所示:
//using System.Runtime.CompilerServices
public static object GetDefault(Type type)
{
// it's very important to check IsValueType before calling GetUninitializedObject
// GetUninitializedObject is valid for reference types, but it will not return null
if (type.IsValueType)
{
return RuntimeHelpers.GetUninitializedObject(type);
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
您可以将其作为单行执行的另一个选项是使用Array.CreateInstance
:
// works for both reference types and value types
static object GetDefault(Type type) => Array.CreateInstance(type, 1).GetValue(0);
Run Code Online (Sandbox Code Playgroud)
编辑:之前的答案建议使用,FormatterServices.GetUninitializedObject
但从 .NET 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.");
Run Code Online (Sandbox Code Playgroud)
推断...
string test = GetDefault(typeof(string));
if (test is string)
Console.WriteLine("This will never be hit.");
Run Code Online (Sandbox Code Playgroud)
我像这样做同样的任务。
//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;
}
Run Code Online (Sandbox Code Playgroud)
表达式可以在这里提供帮助:
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();
}
Run Code Online (Sandbox Code Playgroud)
我没有测试这个片段,但我认为它应该为引用类型生成"类型"空值.