Обобщения: доступ к новым, не скрытым пользователям - PullRequest
1 голос
/ 22 апреля 2009

У меня возникла проблема с генериками и новыми участниками. Я написал общий класс, который работает с объектом типа ObjectA. ObjectB происходит от ObjectA и скрывает несколько членов ObjectA. Когда я предоставляю тип ObjectB в качестве параметра типа для универсального класса, я ожидаю, что когда я вызову любой из членов, скрытых ObjectB, я буду вызывать реализацию ObjectB. Однако CLR по-прежнему вызывает скрытые элементы (реализация ObjectA). Это кажется нелогичным, потому что я явно предоставил тип ObjectB универсальному классу. Это проблема с самими дженериками или я что-то не так делаю?

Редактировать: К сожалению, у меня нет доступа к исходному коду ObjectA, и элемент, который я хочу переопределить, не является виртуальным. Если бы у меня был доступ к исходному коду ObjectA, я бы сделал член виртуальным, но, поскольку я не могу этого сделать, мой единственный вариант «переопределения» члена - через ключевое слово «new».

</p> <pre><code>class GenericClass<T> where T : ObjectA { public void DoWork(T item) { // When type parameter 'T' is ObjectB, should get ObjectB's implementation item.Invoke(); } } class ObjectA { public void Invoke() { // A's implementation... } } class ObjectB : ObjectA { public new void Invoke() { // B's implementation... } } static void Main() { GenericClass<ObjectB> genericClass = new GenericClass<ObjectB>(); ObjectB objectB = new ObjectB(); genericClass.DoWork(objectB); }

Ответы [ 3 ]

7 голосов
/ 22 апреля 2009

Нет. Вызовы, сгенерированные компилятором, относятся к членам , о которых он знает во время компиляции . Это участники, выставленные ObjectA.

По какой причине вы не используете обычное наследование с виртуальными / переопределенными методами?

Кстати, вот еще один пример того же рода вещей - перегруженный оператор == для строк не используется, хотя T равен string в вызове Foo:

using System;

class Test
{
    static bool Foo<T>(T first, T second)
        where T : class
    {
        return first == second;
    }

    static void Main()
    {
        string x = "hello";
        string y = new string(x.ToCharArray());

        Console.WriteLine(Foo(x, y));
    }
}
0 голосов
/ 22 апреля 2009

Вы определяете T как тип ObjectA для вашего универсального. Если бы Invoke () был виртуальным, он работал бы так, как вы думаете, но поскольку это не так, ваш универсальный вызов вызывает реализацию ObjectA, потому что именно так определен T.

Нет записи таблицы виртуальных методов, указывающей на реализацию Invoke () в ObjectB, так что это все, что может вызвать среда выполнения. Если бы это был виртуальный метод, в VMT был бы адрес метода, и он действовал бы так, как вы думаете, что он будет.

0 голосов
/ 22 апреля 2009

Возможно, это не ответ на ваш вопрос, но я не вижу смысла в вашем подходе (возможно, потому, что я вижу только упрощенный пример).

Я бы предложил использовать следующий подход:

class ObjectA
{
    public virtual void Invoke()
    {
        // do some work
    }
}

class ObjectB : ObjectA
{
    public override void Invoke()
    {
        // do some other work
    }
}

class GenericNotNeededClass
{  
    public void DoWork(ObjectA item)  
    {  
        item.Invoke();  
    }  
}  


static void Main()  
{  
    GenericNotNeededClass nonGenericClass = new GenericNotNeededClass();  
    ObjectB objectB = new ObjectB();  
    nonGenericClass.DoWork(objectB);
}

Я полагаю, что код делает то, что вы ищете, основываясь на вашем примере кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...