views:

385

answers:

3

Hi,

In the .net framework, there's a generic IEnumerable<T> interface which inherits from the not-generic IEnumerable, and they both have a GetEnumerator() method. The only differents between these two GetEnumerator() is the return type. Now I have a similar design, but when I compile the code, the compiler said:

MyInterface<T>.GetItem()' hides inherited member 'MyInterface.GetItem()'. Use the new keyword if hiding was intended.

The MyInterface<T>.GetItem() returns a concrete type T, while MyInterface.GetItem() returns type System.Object.

So I think if the BCL team guys compile the .net framework, they will get the same warning.

I think having compiler warnings is not good, what do you think? And how can I solve this problem? I mean I want to get the concrete type T when calling the MyInterface<T>.GetItem() not just a instance of type System.Object.

Thanks in advance! :-)

Supplement: I'm saying the interfaces theirselves: IMyInterface inherits from IMyInterface, and they both have the GetItem() method (the IMyInterface.GetItem() returns type T, while IMyInterface.GetItem() returns type System.Object). The problem is that, if our code only have these two interfaces, that is, no derived concrete classes, we will encounter the compiler warning after compile the source code.

+3  A: 

The difference is that IEnumerable<T> and IEnumerable are interfaces. In a concrete type, that implements both interfaces, at least one of them has to be implemented explicitly.

In a concrete type inheritance you must use the new keyword to indicate that you want to overwrite the method from the base type. When appplying the new keyword the method is not inherited. This means that myTypeInstance.Method will call the method defined on MyType, while ((MyBaseType) myTypeInstance).Method will call the method defined on the base type.

public interface Interface1 {
    object GetItem();
}

public interface Interface2<T> : Interface1 {
    T GetItem();
}

public class MyBaseType : Interface1 {
    public object GetItem() {
        // implements Interface1.GetType()
        return null;
    }
}

public class MyType<T> : Interface1, Interface2<T> {
    public new T GetItem() {
        // Implements Interface2<T>.GetItem()
        return default(T);
    }

    object Interface1.GetItem() {
        // implements Interface1.GetItem()
        return this.GetItem();   // calls GetItem on MyType
    }
}

var myType = new MyType();
var myTypeResult = myType.GetItem(); // calls GetItem on MyType
var myBaseTypeResult = new ((MyBaseType) myType).GetItem(); // calls GetItem on MyBaseType
Obalix
Hi, in my senario, the Interface2<T> inherits from Interface1, then you will get the compiler warning.
Dylan Lin
Should make no difference, as long as one of the GetItem methods is implemented explicitly, i.e. using Interface.GetItem.
Obalix
Hi, there will be a compiler warning, unless I use the "new" keyword. Please see my supplement in the post. :)
Dylan Lin
+5  A: 

They don't because they compile one version as an Explicit Interface Method Implementation. It looks like this:

public class SomeClassThatIsIEnumerable<T> : IEnumerable<T>
{
    public IEnumerator<T> GetEnumerator()
    {
       // return enumerator.
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerator<T>)this).GetEnumerator();
    }
}

What this type of construct does is make the first GetEnumerator method become the default method, while the other GetEnumerator method is only accessible if the caller first casts SomeClassThatIsIEnumerable to the type IEnumerator, so it avoids the problem.

Edit: based on the supplement above, you would want to use the new keyword:

public interface IMyInterface
{
   object GetObject();
}

public interface IMyInterface<T> : IMyInterface
{
   new T GetObject();
}

// implementation:

public class MyClass : IMyInterface<string>
{
    public string GetObject() 
    {
        return "howdy!";
    }

    object IMyInterface.GetObject()
    {
        return GetObject();
    }
}
David Morton
Hi, I'm not saying this, please see my "Supplement" in the post. Thanks :)
Dylan Lin
+1 even though you can't specify access level for an explicit interface implementation
erikkallen
@Dylan: Use the new keyword as the compiler recommends. See my edits above.
David Morton
That works, thanks. But when we check the IEnumerable<T> source code using Reflector, there's no new keywords, so why the BCL team didn't use the "new" keyword?
Dylan Lin
Reflector doesn't show the new keyword. It's there for C# compilation only. That part of the BCL might not have been written in C# anyways. Remember, the compiler warning is a compiler warning from C#, not from the .NET Framework in general. Try compiling the second block of code I showed above. When you open it in Reflector, the "new" keyword is gone.
David Morton
This answer is really what I want, thanks a lot! :)
Dylan Lin
A: 

I also have this problem, I understand the question, but there is no correct answer.

Andy
Hi, David Morton is right. You can take a look at the Mono source code. It use the "new" keyword for IEnumerable<T>.
Dylan Lin
I have solve this problem by new keyword, Reflector has guide me to an wrong direction.
Andy