如何在没有装箱的情况下检查泛型参数是否为空

时间:2017-11-21 22:33:04

标签: c# generics interface overloading boxing

我想编写一个接受单个IBar并调用其Baz方法的方法。

obj为空时抛出:

void Foo<T>(T obj)
    where T : IBar
    => obj.Baz();

当它是值类型时,此框obj

void Foo<T>(T obj)
    where T : IBar
    => obj?.Baz();

如果Baz为零,则不会调用obj

void Foo<T>(T obj)
    where T : IBar
{
    if (!EqualityComparer<T>.Default.Equals(obj, default(T)))
        obj.Baz();
}

在这里,无论Foo(new Bar())是类还是结构,Bar总是选择泛型方法:

void Foo<T>(T obj)
    where T : struct, IBar
    => obj.Baz();

void Foo(IBar obj)
    => obj?.Baz();

这让我的眼睛流血了:

void FooVal<T>(T obj)
    where T : struct, IBar
    => obj.Baz();

void FooRef(IBar obj)
    => obj?.Baz();

那么有最好的做法吗?我对所有建议持开放态度。

编辑:

问题被标记为Generic constraints, where T : struct and where T : class重复,旧标题是。所以我更新了标题以更好地传达我的问题。我要问的是,如果没有装箱,我怎么能调用泛型方法并使用参数,如果它不是空的。

为链接问题解释的一些解决方法可能会用来回答这个问题,但我仍然认为这是一个根本不同的问题。

2 个答案:

答案 0 :(得分:1)

我想出了这个帮手:

public static class Null
{
    public static bool IsNull<T>(T obj) => !Data<T>.HasValue(obj);

    private static class Data<T>
    {
        public static readonly Func<T, bool> HasValue = InitHasValue();

        private static Func<T, bool> InitHasValue()
        {
            var type = typeof(T);
            if (!type.IsValueType)
                return obj => obj != null;

            if (type.IsGenericType &&
                type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                var value = Expression.Parameter(type, "value");
                var getter = type.GetProperty("HasValue").GetMethod;
                var call = Expression.Call(value, getter);
                var lambda = Expression.Lambda<Func<T, bool>>(call, value);
                return lambda.Compile();
            }

            return obj => true;
        }
    }
}

所以我可以这样做:

void Foo<T>(T obj)
    where T : IBar
{
    if (!Null.IsNull(obj)) // Does not box.
        obj.Baz();
}

答案 1 :(得分:1)

刚遇到类似的问题,我提出了以下解决方案:

void Foo<T>(T obj)
{
  if (obj is object)
    obj.Baz();
}

如果is为null,则false操作的结果始终为obj,或者值为null的可空类型为T,如果不是,则检查是否为拳击存在从objectnull的转换,情况总是如此。

除非编译器根本没有优化,否则实际上这应该只是npm run build检查,或者是非可空类型的noop。