我想编写一个接受单个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重复,旧标题是。所以我更新了标题以更好地传达我的问题。我要问的是,如果没有装箱,我怎么能调用泛型方法并使用参数,如果它不是空的。
为链接问题解释的一些解决方法可能会用来回答这个问题,但我仍然认为这是一个根本不同的问题。
答案 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
,如果不是,则检查是否为拳击存在从object
到null
的转换,情况总是如此。
除非编译器根本没有优化,否则实际上这应该只是npm run build
检查,或者是非可空类型的noop。