Как перенаправить все вызовы родительского класса на дочерний класс?

Предположим, у меня есть проект C#, который ссылается на dll, содержащую Class1. Из Project1 я хочу расширить функциональность Class1, используя класс Class2, который наследуется от Class1, а затем я хочу использовать Class2 всякий раз, когда ожидается Class1 (без изменения вызовов Class1, чтобы они указывали на Class2, это ключ).

Кроме того, я должен добавить, что Class1 - это модуль инициализации (в используемой мной структуре), который не вызывается явно (это часть внутреннего механизма). Это означает, что я не могу просто пойти и заменить вызовы Class1 на Class2 после того, как Class2 расширит поведение Class1 в моем коде.

(Как) этого можно достичь?

Еще одна идея, которая только что пришла мне в голову, — использовать частичные классы; однако я сомневаюсь, что полный класс может быть переопределен «позже» как частичный класс вне этой dll.

===== Позднее редактирование: я наткнулся на статью, которая, кажется, предполагает, что это возможно, и я пытаюсь понять, как это сделать. Смотрите, в этой статье RestrictFileTypes (Class2) наследуется от IInitializableModule (Class1), который находится в dll, но не говорится, как Class2 заменяет все вызовы Class1 с этого момента в будущем (http://world.episerver.com/blogs/al-higgs/dates/2012/11/Ограничениетиповфайлов/). Что вы об этом думаете?


person dear1    schedule 20.05.2016    source источник
comment
Итак, если я правильно понимаю, вы хотите оставить свои объявления как var obj = new Class1() и автоматически указывать на Class2... без какого-либо приведения или чего-то еще?   -  person entropic    schedule 20.05.2016
comment
Да, я наткнулся на статью, которая, кажется, предполагает, что это возможно, и я пытаюсь понять, как это было бы очень полезно для меня. Смотрите, в этой статье RestrictFileTypes (Class2) наследуется от IInitializableModule (Class1), который находится в dll, но не говорится, как Class2 заменяет все вызовы Class1 с этого момента в будущем (world.episerver.com/blogs/al-higgs/dates/ 2012/11/).   -  person dear1    schedule 20.05.2016
comment
Еще немного контекста может оказаться полезным. Что такое Class1 и Class2? Какой код использует функциональные возможности Class1 и почему вместо него нужно использовать поведение Class2? Возможно, у вашей проблемы есть более простое решение, чем то, что вы имеете в виду.   -  person Tanner Swett    schedule 20.05.2016
comment
Похоже, вы хотите совершить какой-то взлом. Попробуйте найти Injections.   -  person Dmitriy Zapevalov    schedule 20.05.2016
comment
Таннер, Class2 — это класс во фреймворке; класс отвечает за кучу инициализаций и валидаций, при запуске сайта или при открытии определённых диалоговых окон, например диалог который позволяет мне сохранить определённые типы файлов. Моя цель состоит в том, чтобы разрешить использование большего количества расширений файлов в этом диалоге, для чего я должен изменить условие из метода Class1, который в основном заключен в специфичной для фреймворка dll. Это контекст для краткости. Дмитрий, никакого взлома, просто расширение поведения фреймворка для клиента.   -  person dear1    schedule 20.05.2016
comment
Если нет взлома и нельзя пересобрать некоторые Framework из исходников. Единственный способ состоит в том, что Framework имеет какой-то специальный механизм для его расширения с помощью вашего класса. Итак, если вы уверены, что это возможно (есть и такие), вам следует задать вопрос относительно конкретных Framework и изучить документацию.   -  person Dmitriy Zapevalov    schedule 21.05.2016


Ответы (2)


Я не понимаю второе требование ("Более того..."). Насчет первого я вижу 2 пути.

Вы можете написать class2, а затем поменять местами имена class1 и class2 путем ручного редактирования. Вхождений должно быть немного, только имена файлов cs и конструкторы. Может быть целесообразно сначала использовать промежуточное имя, как вы обычно делаете в операции подкачки. Это, вероятно, будет самым простым и чистым способом, но вы можете не иметь никакого контроля над текущим class1 и не сможете его переименовать. Так вот по другому.

Вы пишете свой class2, снова называя его class1 с самого начала, но в другом пространстве имен. У вас будет class1, происходящий от другого class1 (старого) в другом пространстве имен. Когда вы закончите, поместите директиву using для вашего нового пространства имен в каждый файл, который ссылается на ваш старый class1, и убедитесь, что это последняя строка использования, чтобы она имела приоритет над теми, что над ней. Это должно работать, если текущий класс class1 не является членом того же пространства имен, из которого на него ссылаются. В последнем случае вам пришлось бы вставлять объявления вашего нового пространства имен во все объявления существующего:

namespace ns.of.old.class1
{
    namespace ns.of.new.class1
    {
        [...]
        Some reference to / use of class1
    }
}

Уловка директивы using ненадежна, кто-то может заметить, что директивы расположены не в алфавитном порядке, и щелкнуть их правой кнопкой мыши, выбрав «Удалить и отсортировать». Тогда ваш код может быть сломан или еще хуже: все еще компилируется, но снова использует старый class1.

person Martin Maat    schedule 21.05.2016

Я назвал это полиморфизмом и реализует через наследование, как показано здесь:

using System;

namespace polymorphismExample {
    public class class1 {
        public virtual string A => "I am Class1.A";
        public         string B => "I am Class1.B";
    }
    public class class2 : class1 {
        public override string A => "I am Class2.A";
    //    public override string B => "I am Class1.B";
        public    new   string B => "I am Class2.B";
    }

    class Program {
        static void Main(string[] args) {
            class1 a1_1 = new class1();

            class1 b1_2 = new class2();
            class2 b2_2 = new class2();

            Console.WriteLine("{0}: {1}", "a1_1.A", a1_1.A);
            Console.WriteLine("{0}: {1}", "a1_1.A", a1_1.B);
            Console.WriteLine();

            Console.WriteLine("{0}: {1}", "b1_2.A", b1_2.A);
            Console.WriteLine("{0}: {1}", "b1_2.A", b1_2.B);
            Console.WriteLine();

            Console.WriteLine("{0}: {1}", "b2_2.A", b2_2.A);
            Console.WriteLine("{0}: {1}", "b2_2.A", b2_2.B);
            Console.WriteLine();   
            Console.ReadLine();
        }
    }
}

что дает в качестве вывода:

a1_1.A: I am Class1.A  
a1_1.A: I am Class1.B

b1_2.A: I am Class2.A  
b1_2.A: I am Class1.B

b2_2.A: I am Class2.A  
b2_2.A: I am Class2.B

Обратите внимание, что закомментированная строка в class2 такова, потому что она не может быть скомпилирована; поскольку метод B не является виртуальным в class1. Этот шаблон требует, чтобы class1 НЕ был закрытым классом, и чтобы только методы в class1, помеченные как виртуальные (или, конечно, абстрактные), отображали желаемое поведение: вызываемое поведение class2 даже при вызове переменной, объявленной как имеющая тип class1.

Конечно, всегда переменные должны быть инициализированы с помощью конструктора class2.

person Pieter Geerkens    schedule 21.05.2016