方法,返回可为空的,适用于引用类型和值类型。

huangapple go评论82阅读模式
英文:

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&lt;T&gt;(T obj) //where T : struct
{
    return Random.Shared.Next() &lt; 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&lt;T&gt;(T obj) where T : struct
{
    return Random.Shared.Next() &lt; 100 ? null : obj;
}

But since I also need this functionality with reference types I added:

T? Foo&lt;T&gt;(T obj) where T : class
{
    return Random.Shared.Next() &lt; 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&lt;T&gt;,而在 class(引用类型)情况下只是带有一些元数据注解的 T)。

正如你已经发现的那样,两个重载(具有相同名称的方法)不允许仅在约束上有所不同。

你可以通过引入一个正式的未使用参数,并将其设置为可选,在其中一个重载中解决这个问题。然后你可以这样做:

T? Foo&lt;T&gt;(T obj) where T : struct
{
    return Random.Shared.Next() &lt; 100 ? null : obj;
}

T? Foo&lt;T&gt;(T obj, bool dummy = false) where T : class
{
    return Random.Shared.Next() &lt; 100 ? null : obj;
}

稍后添加: 我想到了另一种方法(hack)你可以尝试。你可以让其中一个重载使用 in 修饰符以只读引用的方式接受参数,而另一个使用标准的按值传递方法。所以:

T? Foo&lt;T&gt;(in T obj) where T : struct
{
    return Random.Shared.Next() &lt; 100 ? null : obj;
}

T? Foo&lt;T&gt;(T obj) where T : class
{
    return Random.Shared.Next() &lt; 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&lt;T&gt; 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&lt;T&gt;(T obj) where T : struct
{
    return Random.Shared.Next() &lt; 100 ? null : obj;
}

T? Foo&lt;T&gt;(T obj, bool dummy = false) where T : class
{
    return Random.Shared.Next() &lt; 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&lt;T&gt;(in T obj) where T : struct
{
    return Random.Shared.Next() &lt; 100 ? null : obj;
}

T? Foo&lt;T&gt;(T obj) where T : class
{
    return Random.Shared.Next() &lt; 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).

huangapple
  • 本文由 发表于 2023年5月6日 21:36:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76189182.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定