程序化等效的默认值(类型)

时间:2008-11-28 10:11:47

标签: c# reflection default

我正在使用反射来遍历Type的属性,并将某些类型设置为默认值。现在,我可以对类型进行切换并明确设置default(Type),但我宁愿在一行中进行。是否存在程序化的默认值?

14 个答案:

答案 0 :(得分:642)

public static object GetDefault(Type type)
{
   if(type.IsValueType)
   {
      return Activator.CreateInstance(type);
   }
   return null;
}

在较新版本的.net(例如.net标准版)中,type.IsValueType需要写为type.GetTypeInfo().IsValueType

答案 1 :(得分:96)

为什么不用反射调用返回默认值(T)的方法?您可以使用任何类型的GetDefault:

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

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

答案 2 :(得分:79)

您可以使用PropertyInfo.SetValue(obj, null)。如果调用值类型,它将为您提供默认值。记录此行为in .NET 4.0in .NET 4.5

答案 3 :(得分:54)

如果您使用的是.NET 4.0或更高版本,而您想要的程序化版本不是代码之外的定义的规则的编码,那么您可以创建Expression,编译并在运行中运行它。

以下扩展方法将使用Type,并通过Expression类的default(T)获取Default method返回的值:

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 :(得分:37)

为什么你说仿制药不合适?

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

答案 5 :(得分:22)

这是优化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;
        }
    }
}

答案 6 :(得分:7)

选择的答案是一个很好的答案,但要小心返回的对象。

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.");

答案 7 :(得分: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();
    }

我没有测试这个片段,但我认为它应该为引用类型生成“类型”空值。

答案 8 :(得分:3)

暂时找不到任何简单而优雅的东西,但我有一个想法:如果你知道你想要设置的属性的类型,你可以编写自己的default(T)。有两种情况 - T是值类型,T是引用类型。您可以通过查看T.IsValueType来查看此信息。如果T是引用类型,则只需将其设置为null即可。如果T是值类型,那么它将具有默认的无参数构造函数,您可以调用它来获取“空白”值。

答案 9 :(得分: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;
    }

答案 10 :(得分:2)

相当于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;
        }
    }
}

答案 11 :(得分: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;
    }

答案 12 :(得分:0)

@Rob Fonseca-Ensor's solution的轻微调整:由于我使用GetRuntimeMethod而不是GetMethod,因此以下扩展方法也适用于.Net Standard。

Option Explicit

Public Sub AddData()
    Dim ws As Worksheet 'define worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet3")

    Dim Deadline As Range 'define deadline range
    Set Deadline = ws.Range("G1")

    Dim Submitted As Range 'define submitted range
    Set Submitted = ws.Range("G3")

    Dim nRow As Long 'find next free row = last used used row +1
    nRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1


    ws.Cells(nRow, "A").Value = Deadline.Value
    ws.Cells(nRow, "B").Value = Submitted.Value

    ws.Cells(nRow, "C").Formula = "=IF(AND(D" & nRow & ">0,ISBLANK(B" & nRow & ")),""NO-DOCUMENT"",IF(AND(D" & nRow & "<=0,NOT(ISBLANK(B" & nRow & "))),""ON-TIME"", IF(AND(D" & nRow & " > 0,NOT(ISBLANK(B" & nRow & "))),""DELAYED"")))"
    ws.Cells(nRow, "D").Formula = "=IF(COUNT(A" & nRow & ":B" & nRow & ")=2,B" & nRow & "-A" & nRow & ",IF(B" & nRow & "="""",""0""))"
End Sub

...以及关心质量的人员的相应单元测试:

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

答案 13 :(得分:0)

这应该起作用: Nullable<T> a = new Nullable<T>().GetValueOrDefault();