当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《程序化等效的默认值(类型)》经验,为你挑选了8个好方法。

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



1> Dror Helper..:

如果值类型使用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


这将返回一个盒装值类型,因此不是默认值(Type).然而,它与你没有泛型的情况一样接近.
所以呢?如果你找到一个类型`default(T)!=(T)(object)default(T)&&!(default(T)!= default(T))`那么你有一个参数,否则无关紧要它是盒装还是不装盒,因为它们是等价的.
谓词的最后一部分是避免操作符重载的欺骗行为......可以使`default(T)!= default(T)`返回false,这就是作弊!=)
这对我有很大帮助,但我认为我应该添加一些可能对搜索这个问题的人有用的东西 - 如果你想要一个给定类型的_array_,你也可以通过使用`Array来获得它. CreateInstance(类型,长度)`.
您不担心创建未知值类型的实例吗?这可能会产生附带影响.
如果允许在结构上定义自定义无参数构造函数(可能在C#6中),则这将不再是正确的解决方案.
这对`System.Net.IPAddress`不起作用,因为该类不提供无参数构造函数.`default(IPAddress)`但确实有效,是`IPAddress.None`.不确定如何使用运行时类型执行此操作.
只是一个注释(在这7(!)年回答中):使用`Activator.CreateInstance`比使用带有`GetConstructor`的反射来存储对任何值类型的构造函数的引用(重用)要慢一些.它是否隐藏(与@Jannes示例一样)并不重要.使用泛型它可以做更多的工作,但仍然要快得多.当然,使用反射的人往往不期望速度,但仍然如此.
@Jannes为什么不呢?IPAddress是引用类型,因此应该只返回null?

2> drake7707..:

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

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

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


这很棒,因为它很简单.虽然这不是最好的解决方案,但这是一个重要的解决方案,因为这种技术在很多类似的情况下都很有用.
如果可以的话,最好使用`nameof(GetDefaultGeneric)`,而不是``GetDefaultGeneric"`
请记住,此实现比接受的答案慢得多(由于反射).它仍然可行,但您需要为GetMethod()/ MakeGenericMethod()调用设置一些缓存以提高性能.

3> JoelFan..:

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


对于这个特定的问题 - 通过类型的属性循环并将它们设置为"默认" - 这非常有效.我在使用反射从SqlDataReader转换为对象时使用它.
这只适用于您想要填写的房产吗?

4> casperOne..:

如果您使用的是.NET 4.0或更高版本,并且您希望编程版本不是代码之外定义的规则的编码,您可以在Expression运行中创建,编译和运行它.

下面的扩展方法将采取Type,并从返回的值default(T)通过Default方法的Expression类:

public static T GetDefaultValue()
{
    // We want an Func which returns the default.
    // Create that expression here.
    Expression> e = Expression.Lambda>(
        // 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 which returns the default.
    // Create that expression here.
    Expression> e = Expression.Lambda>(
        // 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实例调用此值,并且不要经常使用它,则缓存所消耗的内存可能会超过收益.


'return type.IsValueType?的性能?Activator.CreateInstance(type):null;' 比e.Compile()()快1000倍;
跑一个基准.显然,应该缓存`e.Compile()`的结果,但假设这个方法的速度大约是'long`的14倍.有关基准和结果,请参阅https://gist.github.com/pvginkel/fed5c8512b9dfefc2870c6853bbfbf8b.
出于兴趣,为什么要缓存`e.Compile()`而不是`e.Compile()()`?即类型的默认类型是否可以在运行时更改?如果不是(我认为是这种情况)你可以只存储缓存结果而不是编译表达式,这将进一步提高性能.
@JohnLBevan - 是的,然后使用什么技术来获得结果并不重要 - 所有这些都将具有极快的摊销性能(字典查找).

5> Rob Fonseca-..:

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

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

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



6> 小智..:

这是优化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 typeDefaults =
           new ConcurrentDictionary();

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


可变结构怎么样?您是否知道修改盒装结构的字段是可能的(也是合法的),以便数据发生变化?
返回的简写版本:`return type.IsValueType?typeDefaults.GetOrAdd(type,Activator.CreateInstance):null;`

7> BSick7..:

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

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


@Dror - string是一个不可变的引用类型,而不是值类型.
是的,但这也适用于默认(字符串),与其他所有引用类型一样......

8> Konstantin I..:

表达式可以在这里提供帮助:

    private static Dictionary lambdasMap = new Dictionary();

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

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

推荐阅读
yzh148448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有