【问题标题】:How can I call default(T) with a type? [duplicate]如何使用类型调用 default(T)? [复制]
【发布时间】:2011-04-12 01:27:28
【问题描述】:

在 c# 中,我可以使用 default(T) 来获取类型的默认值。我需要在运行时从System.Type 获取默认类型。我该怎么做?

例如与此类似的东西(不起作用)

var type = typeof(int);
var defaultValue = default(type);

【问题讨论】:

    标签: c# .net reflection


    【解决方案1】:

    对于引用类型返回null,对于值类型,可以尝试使用Activator.CreateInstance或调用该类型的默认构造函数。

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

    【讨论】:

    • 写完我的问题后不久,我想出了return Expression.Lambda<Func<object>>(Expression.Convert(Expression.Default(type), typeof (object))).Compile()();,但你的要好得多。
    • @Giddy:这将是一种非常昂贵的方法,因为您在每次调用时都将表达式树编译为 IL(然后 JIT 必须将其编译为本机)。跨度>
    • 是的,我同意。这就是为什么我不使用它,而是使用 madgnome 的解决方案。虽然,促使我使用他的代码的是更短、更易读的代码,而不是性能。对于我的场景来说,性能并不是什么大问题。
    【解决方案2】:

    如果您要构建表达式树,请使用Expression.Default

    Expression expression = Expression.Default(type);
    

    可以相当轻松地做到这一点的另一种方法是:

    object defaultValue = Array.CreateInstance(type, 1).GetValue(0);
    

    丑陋,但它会工作 :) 请注意,很难获得可空类型的默认值,因为它总是被装箱到空引用。

    如 cmets 中所述,有一些模糊的场景(void 和指针类型)它们不等价,但它们是极端情况 :)

    【讨论】:

    • 我正在生成用于 Mindscape Lightspeed 的表达式树,但他们的查询提供程序不支持 DefaultExpression,因此我需要将实际值放入 ConstantExpression
    • 最轻微的吹毛求疵,指针类型的行为是不同的。 default(int*) 返回 IntPtr.Zero,而 Default(typeof(int*)) 抛出。我发现的另一个不为人知的领域是System.Void,你不能做default(void),而Default(typeof(void)) 返回null。没什么大不了的,以防万一有人想照顾..
    • @nawfal:为此添加了注释,谢谢。
    【解决方案3】:

    这很简单,您只需考虑两种情况:

    • 引用类型:默认值始终为空
    • 值类型:您可以使用Activator.CreateInstance轻松创建实例

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

    您也可以考虑使用FormatterServices.GetUninitializedObject 而不是Activator.CreateInstance,它可能更快。

    【讨论】:

    • 你试过运行你的代码吗?它不起作用,原因是值类型(通常)没有默认构造函数。他们在 C# 中做,但这是虚构的;在 CLR 级别上没有,initobj 在 IL 中使用。
    • @Pavel,你说得对,我从来没有意识到没有真正的默认构造函数...我将其更改为 Activator.CreateInstance,它工作正常
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-07
    • 1970-01-01
    • 2018-12-05
    • 2016-03-15
    • 2014-10-01
    相关资源
    最近更新 更多