【问题标题】:Generic extension method for retrieving 'default' value?检索“默认”值的通用扩展方法?
【发布时间】:2013-09-30 23:15:46
【问题描述】:

根据此处的示例,我正在尝试确定对象的默认值:

https://stackoverflow.com/a/3195792/1293496

这个特定的扩展方法是为 System.Type 创建的。我试图完成的是让它更加通用,我可以做这样的事情:

int i = 3;
bool amIaDefaultValue = i.IsDefaultValue();

如果 i == 0(int 的默认值),我希望它返回 true,而对于所有其他实例返回 false。

这是我最初的尝试:

public static bool IsDefaultValue<T>(this T value)
{
    var t = typeof(T); // always comes back as object..?

    if (t.IsValueType && Nullable.GetUnderlyingType(t) == null)
    {
        return value.Equals(Activator.CreateInstance<T>());
    }
    else
    {
        var defaultValue = default(T);

        if (value == null)
            return defaultValue == null;
        else
            return value.Equals(defaultValue);
    }
}

从好的方面来说,我可以将 .IsDefaultValue() 附加到任何对象。不幸的是,T 的类型总是返回为 System.Object。如果我这样设置,我可以得到正确的类型:

var t = typeof(value);

但如果该值恰好为 null,我会立即收到错误消息。有没有很好的解决方法来实现这样的扩展方法?还是我应该坚持示例中经过验证的路线?

编辑 正如 cmets 所指出的,我似乎有点过于简单化了,错过了问题的根源。这实际上是调用我的 IsDefaultValue():

foreach (var imprintProperty in deltas.GetType().GetProperties())
{
    var value = imprintProperty.GetValue(deltas);
    if (!value.IsDefaultValue())
    {
        // get corresponding prop in programmable area
        var programmableProp = progarea.GetType().GetProperty(imprintProperty.Name);
        if (programmableProp != null)
            programmableProp.SetValue(progarea, value);
    }
}

现在很明显,.GetValue 总是作为 System.Object 返回。呃。

是否仍然可以在扩展方法中将对象视为其底层类型?很抱歉与此混淆。

【问题讨论】:

  • 我没有看到您描述的行为,使用3.IsValueDefault() 调用您的方法并在您的扩展方法中添加Console.WriteLine(t) 会在控制台上产生预期的System.Int32typeof(value) 在您的方法中也是编译器错误。你没有告诉我们什么?
  • 我也无法重现“总是得到对象”作为类型。
  • 当您调用该方法时,您是否确定 idesign-time 类型称为int?比如,你没有类似的东西:object i = 3; bool amIaDefaultValue = i.IsDefaultValue();? (顺便说一句,可以说你可能想要使用value.GetType()(检查空值!),就好像你传入一个值类型作为基础object 将它作为接口传递它正在实施,您将得到不正确的结果,因为 default(T) 将返回 null)
  • 我不明白这个问题,但要验证something 是否具有默认值并不像public static bool IsDefaultValue&lt;T&gt;(this T value) { return value == null || value.Equals(default(T)); } 这样简单?
  • (续)这对您来说可能不是一个可行的解决方案。除非您需要检查由值类型实现的接口,否则我认为您可以简单地检查 null 并始终返回 true,否则像现在一样进行值类型检查。如果是引用类型且值为非空,则返回false。如果是值类型,请对照默认实例进行检查。

标签: c# generics extension-methods


【解决方案1】:

看看这个:

static class Program
{
    static void Main()
    {
        int a = 1;

        Console.WriteLine("a.IsDefaultValue() : " + a.IsDefaultValue());

        a = 0;

        Console.WriteLine("a.IsDefaultValue() : " + a.IsDefaultValue());

        object obj = new object();

        Console.WriteLine("obj.IsDefaultValue() : " + obj.IsDefaultValue());

        obj = null;

        Console.WriteLine("obj.IsDefaultValue() : " + obj.IsDefaultValue());

        int? b = 1;

        Console.WriteLine("b.IsDefaultValue() : " + b.IsDefaultValue());

        b = null;

        Console.WriteLine("b.IsDefaultValue() : " + b.IsDefaultValue());

        Console.ReadKey(true);
    }

    static bool IsDefaultValue<T>(this T value)
    {
        if (ReferenceEquals(value, null))
        {
            return true;
        }

        var t = value.GetType();

        if (t.IsValueType)
        {
            return value.Equals(Activator.CreateInstance(value.GetType()));
        }

        return false;
    }
}

显然有效(我不得不说我确信另一种方法应该有效,但不是)

【讨论】:

  • 对于整数?类型,IsDefaultValue() 为 0 和 null 返回 true。它应该只为 null 返回 true。我的印象是 Nullable 类型和泛型不能很好地结合在一起。
猜你喜欢
  • 2011-07-24
  • 2018-05-03
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 2019-01-28
相关资源
最近更新 更多