class Control
{
protected:
virtual void SomeMethod()
{
//Делает то, что нужно
}
};
class SomeStandatdControl : public Control
{
protected:
virtual void SomeMethod()
{
//Делает не то, что нужно
}
};
class MyControl : public SomeStandatdControl
{
protected:
virtual void SomeMethod()
{
//Вот тут вызов нужного метода через явную квалификацию
Control::SomeMethod();
}
};
А теперь вопрос, как такое написать на шарпе?
public class Control
{
protected virtual void SomeMethod()
{
//Делает то, что нужно
}
}
public class SomeStandatdControl : Control
{
protected override void SomeMethod()
{
//Делает не то, что нужно
}
}
public class MyControl : SomeStandatdControl
{
protected override void SomeMethod()
{
//Как тут вызвать Control.SomeMethod???
Control.SomeMethod(); // Error: Cannot access protected member
(this as Control).SomeMethod(); // Error: Cannot access protected member
}
}
public class Control
{
protected virtual void SomeMethod()
{
SomeMethodOfControl();
}
protected void SomeMethodOfControl()
{
//Делает то, что нужно
}
}
public class SomeStandatdControl : Control
{
protected override void SomeMethod()
{
//Делает не то, что нужно
}
}
public class MyControl : SomeStandatdControl
{
protected override void SomeMethod()
{
//Как тут вызвать Control.SomeMethod???
//Control.SomeMethod(); // Error: Cannot access protected member
//(this as Control).SomeMethod(); // Error: Cannot access protected member
SomeMethodOfControl();
}
}
иначе никак.
для вызова предыдущего в цепочке: base.SomeMethod();
Надо пока не поздно написать в МС, может, в следующей версии добавят. :crush: Хотя ты первый, кому это понадобилось.
Тут проблема в том, что обычно такие вещи в диезе разруливаются путем приведения экземпляра нужному типу. Т.е. если есть экз. типа С (потомка В, который в свою очередь потомок А), то нужный метод вызывается путем приведения к типу А. Однако в данном случае это не помогает
Это вопрос-то скорее философский. Если разработчик базового класса сделал свою реализацию — зачем вам лезть дальше в дебри дерева наследования, чтобы вытащить что-то оттуда из самого нутре? Мало ли зачем он его перегрузил — может он там состояние объекта своего меняет? А вы хотите в обход его реализации пойти.
А если Вы сами разрабочик обоих классов — легко сделаете то что например я предлагал, если уж не хочется повторять реализацию.
D_S>Здравствуйте, Воронков Василий, Вы писали:
ВВ>>Уроды, в общем.
D_S>Согласен. Кто мешал сделать что-либо наподобие: D_S>
Здравствуйте, Алексей Одинцов, Вы писали:
АО>Здравствуйте, Dr_Sh0ck, Вы писали:
АО>Это вопрос-то скорее философский. Если разработчик базового класса сделал свою реализацию — зачем вам лезть дальше в дебри дерева наследования, чтобы вытащить что-то оттуда из самого нутре? Мало ли зачем он его перегрузил — может он там состояние объекта своего меняет? А вы хотите в обход его реализации пойти.
Вот именно меняет. Только одна маленькая деталь, не своего объекта, а уже нашего общего. Могу же я у собственного объекта сам выбирать поведение. И это поведение уже на 80% реализовано в пред-базовом, а потом в базовом урезано. Да дело даже не в этом. В данной ситуации я не могу вызвать защищенный метод своего предка. Доступ к защищенным методам предка это мое законное право как наследника, а тут меня его лишают. Какого хрена? В чем тут логика или хотябы философия???
Здравствуйте, IvanM, Вы писали:
IM>Здравствуйте, Алексей Одинцов, Вы писали:
АО>>Здравствуйте, Dr_Sh0ck, Вы писали:
АО>>Это вопрос-то скорее философский. Если разработчик базового класса сделал свою реализацию — зачем вам лезть дальше в дебри дерева наследования, чтобы вытащить что-то оттуда из самого нутре? Мало ли зачем он его перегрузил — может он там состояние объекта своего меняет? А вы хотите в обход его реализации пойти.
IM>Вот именно меняет. Только одна маленькая деталь, не своего объекта, а уже нашего общего. Могу же я у собственного объекта сам выбирать поведение. И это поведение уже на 80% реализовано в пред-базовом, а потом в базовом урезано. Да дело даже не в этом. В данной ситуации я не могу вызвать защищенный метод своего предка. Доступ к защищенным методам предка это мое законное право как наследника, а тут меня его лишают. Какого хрена? В чем тут логика или хотябы философия???
в том же, почему и некоторые члены вашего предка вам недоступны (are private). Разработчик вашего базового класса сделал свою реализацию, деталей которой вы не знаете. Если позволить вам исключить из работы его функциональность — его (и ваш) класс станет вести себя неправильно. Если вам очень хочется вызвать Control.SomeMethod() — унаследуйтесь напрямую от него и повторите реализацию так как вам нравится, либо уж используйте базовый класс таким какой он есть.
Если же вы сами разработчик всех трех классов — значит учитесь правильнее проектировать иерархии классов.
Здравствуйте, Алексей Одинцов, Вы писали:
АО>Здравствуйте, IvanM, Вы писали:
IM>>Здравствуйте, Алексей Одинцов, Вы писали:
АО>в том же, почему и некоторые члены вашего предка вам недоступны (are private). Разработчик вашего базового класса сделал свою реализацию, деталей которой вы не знаете. Если позволить вам исключить из работы его функциональность — его (и ваш) класс станет вести себя неправильно. Если вам очень хочется вызвать Control.SomeMethod() — унаследуйтесь напрямую от него и повторите реализацию так как вам нравится, либо уж используйте базовый класс таким какой он есть.
АО>Если же вы сами разработчик всех трех классов — значит учитесь правильнее проектировать иерархии классов.
Я не говорю здесь про private, это совершенно другое, о них не пишут в документации, их вобще нет. Раз уж дело дошло до обсуждения вопросов проектирования, то мое мнение — любое дублирование кода (кода предка в наследнике в частности) ведет к проблемам при последующей поддержке в целостном состоянии. И тут любая разумная возможность повторного использования кода — благо. В данном случае, IMHO, ситуация разумная. По поводу иерархии
1. Не всегда мы можем все спроектировать сами, иногда это уже сделали за нас.
2. Идеальные иерархии в реальной жизни попадаются не всегда.
А что касается "вести себя неправильно", откуда такая уверенность, что непременно все начнет вети себя неправильно? Точно так же можно запретить доступ к защищеннвм полям класса. А вдруг мы их изменим и все начнет вести себя неправильно? Это паранойя а не логика.
реализация функции — её код — такая же private как и приватные члены класса. то, что вам доступно вызвать её не говорит о том, что вы можете делать предположения о её коде.
если вы сами проектируете иерархии — у вас есть выход.
если не сами — Вам придется следовать логике программиста создавшего для Вас базовый класс. Вам не нравится его логика — напишите свой класс со своей. Если это невозможно по каким-то причинам (например, вы вынуждены использовать его как базовый) — увы. придется выкручиваться.
Но логика в таком подходе есть. Не сказал бы что я её разделяю, но мне всего пару раз пришлось столкнуться с этим ограничичением, и не могу сказать что оно такое уж драконовское. В C# и шаблонов пока нет, ну и что теперь? Хотите писать как на C++ — пишите на C++. Или пишите в MS пусть сделают эту Вашу фичу. Я ей применение тоже найду, хоть пока и не считаю её такой уж нужной.
Здравствуйте, Алексей Одинцов, Вы писали:
АО>Но логика в таком подходе есть. Не сказал бы что я её разделяю, но мне всего пару раз пришлось столкнуться с этим ограничичением, и не могу сказать что оно такое уж драконовское. В C# и шаблонов пока нет, ну и что теперь? Хотите писать как на C++ — пишите на C++. Или пишите в MS пусть сделают эту Вашу фичу. Я ей применение тоже найду, хоть пока и не считаю её такой уж нужной.
Вобщем, понятна логика. Во первых, С++ это не C#, а во вторых, ООП это не то, что я о нем думаю. Но, в любом случае, спасибо за ответ!
Здравствуйте, IvanM, Вы писали:
IM>Вот именно меняет. Только одна маленькая деталь, не своего объекта, а уже нашего общего. Могу же я у собственного объекта сам выбирать поведение. И это поведение уже на 80% реализовано в пред-базовом, а потом в базовом урезано. Да дело даже не в этом. В данной ситуации я не могу вызвать защищенный метод своего предка. Доступ к защищенным методам предка это мое законное право как наследника, а тут меня его лишают. Какого хрена? В чем тут логика или хотябы философия???
public class A
{
private ArrayList _list;
public A()
{
Init();
}
protected virtual void Init()
{
_list = new ArrayList();
}
public virtual void Add(object item)
{
_list.Add(item);
}
}
public class B : A
{
private ArrayList _list2;
protected override void Init()
{
base.Init();
_list2 = new ArrayList();
}
public override void Add(object item)
{
base.Add(item);
_list2.Add(item);
}
}
public class C
{
protected override void Init()
{
((B)this).Init();
}
}
...
C c = new C();
c.Add(25); // Null reference exception
Попробуй через делегаты. В Delphi обычная практика через TMethod.
Через рефлектор или CreateDelegate найти адрес метода и вствить его в соответствующее поля делегата, а на место ссылки на объект this.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>Через рефлектор или CreateDelegate найти адрес метода и вствить его в соответствующее поля делегата, а на место ссылки на объект this.
Не выйдет.
Делегат — не адрес метода, он намертво с объектом-владельцем метода связан. А как раз-таки ссылку на "объект-дедушку" вычислить не получится. Боюсь, что в VTBL текущего обекта даже упоминания нет про "дедушкин" метод. Такое пройдет только со статическим методом или если "дед" сам такой делегат вернет.
Здравствуйте, Dax, Вы писали:
Dax>Делегат — не адрес метода, он намертво с объектом-владельцем метода связан. А как раз-таки ссылку на "объект-дедушку" вычислить не получится. Боюсь, что в VTBL текущего обекта даже упоминания нет про "дедушкин" метод. Такое пройдет только со статическим методом или если "дед" сам такой делегат вернет.
Почему же, делегат как раз имеет списочную структуру типа TMethod. А вот как выдернуть ссылку на дедушкин метод это другая проблема. Если это не абстрактный класс или через неабстрактного наследника не перекрывающего этот метод адрес выдернуть метода выдернуть можно просто создав объект этого типа создать делегат с его методом и заменить ссылку на объект на this.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Почему же, делегат как раз имеет списочную структуру типа TMethod. А вот как выдернуть ссылку на дедушкин метод это другая проблема. Если это не абстрактный класс или через неабстрактного наследника не перекрывающего этот метод адрес выдернуть метода выдернуть можно просто создав объект этого типа создать делегат с его методом и заменить ссылку на объект на this.
Чистой воды хак. К тому же со многими "если". Я имел ввиду стандартные("цивилизованные") средства.
Замечу, что такого рода действия могут очень огорчить GC.
Здравствуйте, Dax, Вы писали:
Dax>Здравствуйте, Serginio1, Вы писали:
S>> Почему же, делегат как раз имеет списочную структуру типа TMethod. А вот как выдернуть ссылку на дедушкин метод это другая проблема. Если это не абстрактный класс или через неабстрактного наследника не перекрывающего этот метод адрес выдернуть метода выдернуть можно просто создав объект этого типа создать делегат с его методом и заменить ссылку на объект на this.
Dax>Чистой воды хак. К тому же со многими "если". Я имел ввиду стандартные("цивилизованные") средства. Dax>Замечу, что такого рода действия могут очень огорчить GC.
Ну а что же остается делать. В Паскале и не на такое идут. А GC только дедушкин объект и не найдет.
Интересно а каким образом он огорчается???
и солнце б утром не вставало, когда бы не было меня
S> Ну а что же остается делать. В Паскале и не на такое идут. А GC только дедушкин объект и не найдет.
Дык из Паскаля из "нетакого" еще и сухим выйти можно. А тут у managed-делегата на _target memcopy предлагается.
private RuntimeMethodInfo _method;
private IntPtr _methodPtr;
private IntPtr _methodPtrAux;
private object _target; //- он самый
S>Интересно а каким образом он огорчается???
У него проблемы с памятью начинаются, в прямом смыле — жуткий склероз
А потом, плачет наверное, тихенько-тихенько
оно read-only. поэтому через делегат это провернуть не получится. только если в unsafe поменять напрямую в памяти указатели. только грязными хаками можно это сделать.
Здравствуйте, Dax, Вы писали:
S>> Ну а что же остается делать. В Паскале и не на такое идут. А GC только дедушкин объект и не найдет.
Dax>Дык из Паскаля из "нетакого" еще и сухим выйти можно. А тут у managed-делегата на _target memcopy предлагается.
Dax>
Dax>private RuntimeMethodInfo _method;
Dax>private IntPtr _methodPtr;
Dax>private IntPtr _methodPtrAux;
Dax>private object _target; //- он самый
Dax>
S>>Интересно а каким образом он огорчается??? Dax>У него проблемы с памятью начинаются, в прямом смыле — жуткий склероз Dax>А потом, плачет наверное, тихенько-тихенько
Сейчас уже не помню, но к _target напрямую обращались (сейчас Нет под рукой Net), но можно и через рефлексию его установить, тогда думаю GC будет веселее.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Алексей Одинцов, Вы писали:
АО>object Target { get; }
АО>оно read-only. поэтому через делегат это провернуть не получится. только если в unsafe поменять напрямую в памяти указатели. только грязными хаками можно это сделать.
А через отображение через FldInfo ????
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Dax, Вы писали:
Y_M>>IMO не будет с CG ничего страшного. При слудующей сборке мусора он наверное просто не найдёт ссылку на подменённый объект и его убъёт из кучи
Dax>Угу, а
Dax>
Здравствуйте, Алексей Одинцов, Вы писали:
АО>Здравствуйте, Serginio1, Вы писали:
S>> А через отображение через FldInfo ????
АО>а кто вам его даст?
А разве нет такого флага BindingFlags.Private ????
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Алексей Одинцов, Вы писали:
АО>Здравствуйте, Serginio1, Вы писали:
S>> А через отображение через FldInfo ????
АО>а кто вам его даст?
Можно вообще эту проблему через отображение решить
mi=ТипДедушки.GetMethod("SomeMethod",BindingFlags.Protected | BindingFlags.Instance);
mi.Invoke(this,new object[]);
Просто через делегаты быстрее если ее часто использовать http://www.rsdn.ru/Forum/?mid=395620
S>Можно вообще эту проблему через отображение решить
S>mi=ТипДедушки.GetMethod("SomeMethod",BindingFlags.Protected | BindingFlags.Instance); S> mi.Invoke(this,new object[]); S> Просто через делегаты быстрее если ее часто использовать
Опять мимо.
В этом случае вызовется свой метод, а не деда. (к слову, нет такого BindingFlags.Protected есть BindingFlags.NonPublic)
Здравствуйте, Dax, Вы писали:
S>>Можно вообще эту проблему через отображение решить
S>>mi=ТипДедушки.GetMethod("SomeMethod",BindingFlags.Protected | BindingFlags.Instance); S>> mi.Invoke(this,new object[]); S>> Просто через делегаты быстрее если ее часто использовать
Dax>Опять мимо. Dax>В этом случае вызовется свой метод, а не деда. (к слову, нет такого BindingFlags.Protected есть BindingFlags.NonPublic)
А как через установку _target челез филдИнфо ????
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Dax, Вы писали:
S>>Можно вообще эту проблему через отображение решить
S>>mi=ТипДедушки.GetMethod("SomeMethod",BindingFlags.Protected | BindingFlags.Instance); S>> mi.Invoke(this,new object[]); S>> Просто через делегаты быстрее если ее часто использовать
Dax>Опять мимо. Dax>В этом случае вызовется свой метод, а не деда. (к слову, нет такого BindingFlags.Protected есть BindingFlags.NonPublic)
Считаешь, что mi вернет не прямой адрес, а ссылку на VMT ????
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Считаешь, что mi вернет не прямой адрес, а ссылку на VMT ????
Естественно, метод же виртуальный.
С FieldInfo тоже облом — не отдает .NET fieldInfo на _target.
Я ж говорю: по честному никак не получится, а хак, он и в Африке на следующей версии .NET прекратит работу.
Здравствуйте, Dax, Вы писали:
Dax>Здравствуйте, Serginio1, Вы писали:
S>> Считаешь, что mi вернет не прямой адрес, а ссылку на VMT ????
Dax>Естественно, метод же виртуальный.
Dax>С FieldInfo тоже облом — не отдает .NET fieldInfo на _target. Dax>Я ж говорю: по честному никак не получится, а хак, он и в Африке на следующей версии .NET прекратит работу.
Не должны быть еще хитрые методы. Извини, если не в лом посмотри из своих классов
можно ли через fieldInfo на приватные поля влиять. У меня сейчас Нет Net, а очень интересно.
и солнце б утром не вставало, когда бы не было меня
S> Не должны быть еще хитрые методы. Извини, если не в лом посмотри из своих классов S>можно ли через fieldInfo на приватные поля влиять. У меня сейчас Нет Net, а очень интересно.
На свои влиять можно (в смысле своих классов). А наследник от System.Delegate _target уже не видит.
Здравствуйте, Dax, Вы писали:
S>> Не должны быть еще хитрые методы. Извини, если не в лом посмотри из своих классов S>>можно ли через fieldInfo на приватные поля влиять. У меня сейчас Нет Net, а очень интересно.
Dax>На свои влиять можно (в смысле своих классов). А наследник от System.Delegate _target уже не видит.
Спасибо. Борцы хреновы. Унсейф . А через рефакторинг _target видно???
и солнце б утром не вставало, когда бы не было меня
S> Спасибо. Борцы хреновы. Унсейф . А через рефакторинг _target видно???
Через reflection видно. Ты был на половину прав
Короче, _target меняется следющим образом:
//public delegate void MethodDelegate();
//
A a = new A();
Delegate am = Delegate.CreateDelegate(typeof(MethodDelegate), a, "Method");
FieldInfo d = am.GetType().BaseType.BaseType.GetField("_target", BindingFlags.Instance | BindingFlags.NonPublic);
d.SetValue(am, this);
am.DynamicInvoke(null);
самое смешное, что все нормально работает, _target меняется, но! вызывается свой же метод, а не "деда".
Здравствуйте, Dax, Вы писали:
S>> Спасибо. Борцы хреновы. Унсейф . А через рефакторинг _target видно???
Dax>Через reflection видно. Ты был на половину прав
Dax>Короче, _target меняется следющим образом:
Dax>
Dax>//
Dax>public delegate void MethodDelegate();
Dax>//
Dax>A a = new A();
Dax>Delegate am = Delegate.CreateDelegate(typeof(MethodDelegate), a, "Method");
Dax>FieldInfo d = am.GetType().BaseType.BaseType.GetField("_target", BindingFlags.Instance | BindingFlags.NonPublic);
Dax>d.SetValue(am, this);
Dax>am.DynamicInvoke(null);
Dax>
Dax>самое смешное, что все нормально работает, _target меняется, но! вызывается свой же метод, а не "деда".
А ты без DynamicInvoke
delegate void procedureWithOutParameters();
Слава Dax. Еще проще чем в Delphi. Dax>Без DynamicInvoke все ok. (c) Пушкин
Dax>Дед вызывается. Не знаю на сколько это функционально в пределах нормального приложения, но простые тесты показывают, что метод вызывается.
А куда он денется. Делегату по барабану, что у него в полях содержится, тупо загоняет параметры и Call по адресу.
А при DynamicInvoke он уже отображение подключает и не работает на прямую.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Dax, Вы писали:
Dax>Здравствуйте, Serginio1, Вы писали:
S>>А ты без DynamicInvoke
Dax>Без DynamicInvoke все ok. (c) Пушкин
Dax>Дед вызывается. Не знаю на сколько это функционально в пределах нормального приложения, но простые тесты показывают, что метод вызывается.
Тыы бы полный код привел, а я тебе большую оценочку поставил.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Dax, Вы писали:
Dax>>Здравствуйте, Serginio1, Вы писали:
S>>>Через рефлектор или CreateDelegate найти адрес метода и вствить его в соответствующее поля делегата, а на место ссылки на объект this.
Dax>>Не выйдет. Dax>>Делегат — не адрес метода, он намертво с объектом-владельцем метода связан. А как раз-таки ссылку на "объект-дедушку" вычислить не получится. Боюсь, что в VTBL текущего обекта даже упоминания нет про "дедушкин" метод. Такое пройдет только со статическим методом или если "дед" сам такой делегат вернет. S> Почему же, делегат как раз имеет списочную структуру типа TMethod. А вот как выдернуть ссылку на дедушкин метод это другая проблема. Если это не абстрактный класс или через неабстрактного наследника не перекрывающего этот метод адрес выдернуть метода выдернуть можно просто создав объект этого типа создать делегат с его методом и заменить ссылку на объект на this.
Кстати, через MethodInfo.MethodHandle.GetFunctionPointer(); можно вытащить любой метод типа и соответственно заполнив структур делегата все сделать и без создания дедушкиного объекта.
и солнце б утром не вставало, когда бы не было меня