英文:
Method that returns nullable that works for reference- as well as value types
问题
I started like that:
T? Foo<T>(T obj) //where T : struct
{
return Random.Shared.Next() < 100 ? (T?)null : (T?)obj;
}
which leads to this error:
Cannot convert null to 'type' because it is a non-nullable value type
Then I added a struct constraint and it worked:
T? Foo<T>(T obj) where T : struct
{
return Random.Shared.Next() < 100 ? null : obj;
}
But since I also need this functionality with reference types I added:
T? Foo<T>(T obj) where T : class
{
return Random.Shared.Next() < 100 ? null : obj;
}
But this makes the compiler say that "Type 'class' already defines a member called 'member' with the same parameter types". How can I resolve this problem without having to give such methods always different names such as FooValueType and FooReferenceType?
英文:
I started like that:
T? Foo<T>(T obj) //where T : struct
{
return Random.Shared.Next() < 100 ? (T?)null : (T?)obj;
}
which leads to this error:
> Cannot convert null to 'type' because it is a non-nullable value type
Then I added a struct contraint and it worked:
T? Foo<T>(T obj) where T : struct
{
return Random.Shared.Next() < 100 ? null : obj;
}
But since I also need this functionality with reference types I added:
T? Foo<T>(T obj) where T : class
{
return Random.Shared.Next() < 100 ? null : obj;
}
But this make the compiler says that "Type 'class' already defines a member called 'member' with the same parameter types". How can I resolve this problem without having to give such methods always different names such as FooValueType and FooReferenceType?
答案1
得分: 2
你无法真正解决这个问题。这两种情况不能是相同的重载,因为返回参数类型 T?
在两种情况下意义相差太大(在 struct
(值类型)情况下表示 System.Nullable<T>
,而在 class
(引用类型)情况下只是带有一些元数据注解的 T
)。
正如你已经发现的那样,两个重载(具有相同名称的方法)不允许仅在约束上有所不同。
你可以通过引入一个正式的未使用参数,并将其设置为可选,在其中一个重载中解决这个问题。然后你可以这样做:
T? Foo<T>(T obj) where T : struct
{
return Random.Shared.Next() < 100 ? null : obj;
}
T? Foo<T>(T obj, bool dummy = false) where T : class
{
return Random.Shared.Next() < 100 ? null : obj;
}
稍后添加: 我想到了另一种方法(hack)你可以尝试。你可以让其中一个重载使用 in
修饰符以只读引用的方式接受参数,而另一个使用标准的按值传递方法。所以:
T? Foo<T>(in T obj) where T : struct
{
return Random.Shared.Next() < 100 ? null : obj;
}
T? Foo<T>(T obj) where T : class
{
return Random.Shared.Next() < 100 ? null : obj;
}
当然,这意味着在一个重载的体内 obj
是只读的(但在另一个重载中不是),但这可能不是问题(从原则上讲,如果你使用巨大的结构体,它甚至可能提高性能)。
英文:
You cannot really resolve this. The two cases cannot be the same overload because the meaning of the return parameter type T?
is too different in the two cases (it means System.Nullable<T>
in the struct
(value type) case, and just T
with some metadata annotations in the class
(reference type) case).
And as you have discovered, two overloads (methods with identical names) are not allowed to differ at constraint only.
One way you could work around it is by introducing a formal unused parameter that you can make optional, in one of the overloads. Then you have:
T? Foo<T>(T obj) where T : struct
{
return Random.Shared.Next() < 100 ? null : obj;
}
T? Foo<T>(T obj, bool dummy = false) where T : class
{
return Random.Shared.Next() < 100 ? null : obj;
}
Later addition: I came to think of another way (hack) you could try. You could let one of the overloads take the argument by read-only reference with the modifier in
, and the other use a standard by value approach. So:
T? Foo<T>(in T obj) where T : struct
{
return Random.Shared.Next() < 100 ? null : obj;
}
T? Foo<T>(T obj) where T : class
{
return Random.Shared.Next() < 100 ? null : obj;
}
Of course this means obj
is readonly in the body of one overload (but not in the other), but that is probably not an issue (in principle, it may even boost your performance if you use huge structs).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论