最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Nullable generics in methods - needs explanation - Stack Overflow

programmeradmin1浏览0评论

can anyone explain why this is allowed:

class A1
{
    public virtual T? F1<T>(T? t) where T : struct { throw new NotImplementedException(); }
    public virtual T? F1<T>(T? t) where T : class { throw new NotImplementedException(); }

}

while this is not:

class A1
{
    public virtual T? F1<T>(T t) where T : struct { throw new NotImplementedException(); }
    public virtual T? F1<T>(T t) where T : class { throw new NotImplementedException(); }

}

"Type 'A1' already defines a member called 'F1' with the same parameter types"

the difference is that in the second case the arguments are not nullable.

how comes that the signatures are same if in one case it's for value types and in another case for reference types?

can anyone explain why this is allowed:

class A1
{
    public virtual T? F1<T>(T? t) where T : struct { throw new NotImplementedException(); }
    public virtual T? F1<T>(T? t) where T : class { throw new NotImplementedException(); }

}

while this is not:

class A1
{
    public virtual T? F1<T>(T t) where T : struct { throw new NotImplementedException(); }
    public virtual T? F1<T>(T t) where T : class { throw new NotImplementedException(); }

}

"Type 'A1' already defines a member called 'F1' with the same parameter types"

the difference is that in the second case the arguments are not nullable.

how comes that the signatures are same if in one case it's for value types and in another case for reference types?

Share Improve this question edited Jan 25 at 13:17 Aliq Qim asked Jan 18 at 13:33 Aliq QimAliq Qim 1369 bronze badges 2
  • Because in both cases it is simply "generic, one generic parameter" (aka `1) and everything else (including the name T, and any constraints) is secondary details – Marc Gravell Commented Jan 18 at 13:47
  • 1 I recommend you edit the question to show what you mean by "not allowed". Presumably there's a compile-time error - the question would be better if you quoted the exact error code and message in the question. – Jon Skeet Commented Jan 18 at 16:14
Add a comment  | 

3 Answers 3

Reset to default 1

T? means different things, depending on whether T is a value type or reference type.

When T is a value type, T? is syntactic sugar for System.Nullable<T>. When T is a reference type, T? is still T, as far as the runtime is concerned. Nullable reference types is purely a feature of the compiler. It boils down to the compiler doing some compile-time checks to prevent NullReferenceExceptions at runtime.

So really you have just declared two methods taking completely different parameter types. One takes a System.Nullable<T>, and the other takes a reference type T that is annotated at compile-time to be nullable.

If both methods take a parameter of type T, then obviously they are exactly the same except they have different type constraints. Method overloads that differ only in type constraints are not allowed.

You are getting the following compiler error pointing at the second F1 overload:

CS0111: Type 'A1' already defines a member called 'F1' with the same parameter types

This is because the signature is given by the method name and parameter types only. The return type is not part of the signature when it comes to overload resolution. You cannot overload a method only differing in the return type.

In the case of the T? t parameters, the two mean different things for classes and structs.

  • in T? t, where T : struct: T? means Nullable<T>.
  • in T? t, where T : class: T? means T where the compiler allows null to be passed as an argument. But T? is not another type than T. I.e., typeof(T?) (which does not compile) is the same as typeof(T) (this is the very reason the first one does not compile).

See also:

  • Method signatures (C# Programming Guide)
  • C# in Depth / Overloading see "Return types" (Jon Skeet)

I guess my example can be boiled down to this:

class A1
{
    public void F1<T>(T t) where T : struct { throw new NotImplementedException(); }
    public void F1<T>(T t) where T : class { throw new NotImplementedException(); }

}

and the core question would be why doesn't compiler treat generic for structs and generic for class as different param types. I guess there is no logical explanation, it just doesn't. or am I missing something?

发布评论

评论列表(0)

  1. 暂无评论