views:

153

answers:

3

In my base class I have a generic method (ideally this would be a property, but you can't have generic properties) and a non-generic property, both with the same name:

protected static T CurrentUserId<T>()
{
    ...
}

protected static string CurrentUserId
{
    get
    {
        ...
    }
}

However, when I come to use either of them intellisense reports ambiguity between them. Surely, base.CurrentUserId (without parethesese) provides enough clues to the compiler that I want to invoke the non-generic property?

Does anyone know why the compiler struggles with this? Thanks in advance.

+5  A: 

If you leave out the generics, like:

public int Value { get;  set; }

public int Value()
{
    return 1;
}

You also get an error: The Type... already contains a definition for Value

And I can think of one case where there is a clear conflict:

MyDelegate foo = new MyDelegate(Value);
Henk Holterman
Funny how introducing generics into the mix seems to entirely mask this more fundamental issue.
Paul Suart
+8  A: 

The parenthesis don't provide enough information, because you don't always use them. Here's why this wouldn't work:

delegate T MyDelegate<T>();

new MyDelegate(myClass.CurrentUserId)

//are we talking about the method or the property?
Rex M
Good point, thanks
Paul Suart
+3  A: 

Paul's comment regarding how "introducing generics into the mix seems to entirely mask this more fundamental issue" seems true.

I believe that your problem has less to do with generics and more to do with how to appropriately overload a method (I could be wrong on this, but this is what I gather from looking up method overloading). I'm not even sure if a property can be overloaded by a method with the same name, but either way, let's take a quick look at method overloading, which still should demonstrate why your code doesn't work.

You can overload a method of the same name (in your case, the name is CurrentUserId) if the signatures of the methods are different. A signature consists in the following four pieces of information:

  • The name of the method
  • The number of parameters
  • The data types and order of the parameters
  • The parameter modifiers

According to Illustrated C# 2008 by Daniel Solis,

"The return type is not part of the signature--although it is a common mistake to believe that it is."

Let's look at your property and method and see if they might have the same signature according to the four pieces of information provided above:

  • Are the names of the method the same? Yes, CurrentUserId.
  • Are the number of parameters the same? Yes, 0.
  • Are the data types and order of the parameters the same? There are no parameters for either, so yes.
  • Are the parameter modifiers the same? Again, there are no parameters for neither the property nor the method, so yes, they are the same.

When you remove the parameters from the equation, the only thing we have to uniquely identify the type is its name. Also, since the return type of the method (or property) is not part of its signature, it doesn't matter that one type is a string and the other type is a generic. Either way, both have the same signature (because their names are the same and they have no parameters) and the compiler will not be able to appropriately distinguish them.

All of that being said, I'm not sure if this exactly answers your question (or even if I approached it correctly...I gladly welcome corrections in the comments to further my personal understanding). However, I find that approaching the problem by first correctly understanding overloading is very helpful to solving your overall problem of how the compiler is treating your code.

I hope this helps.

Ben McCormack