IEnumerable.GetEnumerator () и IEnumerable <T>.GetEnumerator () - PullRequest
5 голосов
/ 14 марта 2010

В инфраструктуре .net есть универсальный интерфейс IEnumerable<T>, который наследуется от неуниверсального IEnumerable, и у них обоих есть метод GetEnumerator(). Единственная разница между этими двумя GetEnumerator() - это тип возвращаемого значения. Теперь у меня похожий дизайн, но когда я компилирую код, компилятор сказал:

MyInterface<T>.GetItem() 'скрывает унаследованный член' MyInterface.GetItem() '. Используйте новое ключевое слово, если было скрыто.

MyInterface<T>.GetItem() возвращает конкретный тип T, а MyInterface.GetItem() возвращает тип System.Object.

Так что я думаю, что если ребята из команды BCL скомпилируют каркас .net, они получат то же предупреждение.

Я думаю, что иметь предупреждения компилятора нехорошо, как вы думаете? И как я могу решить эту проблему? Я имею в виду, что хочу получить конкретный тип T при вызове MyInterface<T>.GetItem(), а не просто экземпляра типа System.Object.

Заранее спасибо! : -)

Дополнение: Я говорю сами интерфейсы: IMyInterface наследуется от IMyInterface, и у них обоих есть метод GetItem () (IMyInterface.GetItem () возвращает тип T, а IMyInterface.GetItem () возвращает тип System.Object ). Проблема в том, что, если наш код имеет только эти два интерфейса , то есть, нет производных конкретных классов, мы встретим предупреждение компилятора после компиляции исходного кода.

Ответы [ 2 ]

10 голосов
/ 14 марта 2010

Нет, потому что они компилируют одну версию как явную реализацию метода интерфейса.Это выглядит так:

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

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

Что делает этот тип конструкции, так это делает первый метод GetEnumerator методом по умолчанию, в то время как другой метод GetEnumerator доступен только в том случае, если вызывающий объект сначала вызывает SomeClassThatIsIEnumerable для типа IEnumerator,так что это позволяет избежать проблемы.

Редактировать: на основе вышеуказанного дополнения вы хотели бы использовать новое ключевое слово:

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();
    }
}
3 голосов
/ 14 марта 2010

Разница в том, что IEnumerable<T> и IEnumerable являются интерфейсами. В конкретном типе, который реализует оба интерфейса, по крайней мере, один из них должен быть реализован явно.

В конкретном наследовании типов вы должны использовать ключевое слово new, чтобы указать, что вы хотите перезаписать метод из базового типа. При применении нового ключевого слова метод не наследуется. Это означает, что myTypeInstance.Method вызовет метод, определенный для MyType, а ((MyBaseType) myTypeInstance).Method вызовет метод, определенный для базового типа.

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
...