Есть у меня иерархия классов (два уровня), в которой все классы должны иметь статические члены с одинаковыми именами, но разным возвращаемым значением. Вопрос как это сделать? Унаследовать статические члены нельзя (все они будут ссылаться на базовый тип), а copy/paste кода меня как-то не вдохновляет. С другой стороны интерфейсы тут тоже не помогут, т.к. декларировать статические члены не могут. Шаблоны тут то-же не к месту, т.к. не чего передавать в параметра шаблона (<T>). Так что же делать то с этим господа?
Попробую пояснить, что имею ввиду. Шла бы речь о не статических членах я бы сделал так:
class A
{
protected int field;
public A()
{
field = 1;
}
public int Field
{
get { return field; }
}
}
class B : A
{
public B()
{
field = 2;
}
}
...
var a = new A();
var b = new B();
Console.WriteLine(a.Field); // 1
Console.WriteLine(b.Field); // 2
Хотелось бы нечто подобное сделать и со статическими версиями поля field и свойства Field.
Здравствуйте, Cynic, Вы писали:
C>Есть у меня иерархия классов (два уровня), в которой все классы должны иметь статические члены с одинаковыми именами, но разным возвращаемым значением. Вопрос как это сделать?
Не делать так. Элементарнейший выход — создание дополнительного абстрактного метода.
abstract class A
{
public abstract IState GetState();
}
class B : A
{
private static readonly IState state = new ...;
public override IState GetState() => state;
}
Здравствуйте, hardcase, Вы писали:
H>Не делать так. Элементарнейший выход — создание дополнительного абстрактного метода.
H>
H>abstract class A
H>{
H> public abstract IState GetState();
H>}
H>class B : A
H>{
H> private static readonly IState state = new ...;
H> public override IState GetState() => state;
H>}
H>
Угу, только метод GetState должен быть статическим для обоих классов
Здравствуйте, Cynic, Вы писали:
C>Есть у меня иерархия классов (два уровня), в которой все классы должны иметь статические члены с одинаковыми именами, но разным возвращаемым значением.
В общем случае так делать низзя, т.к. добавление нового типа-наследника и вэлкам
var derived = Derived.Instance; // oops, Instance property was inherited from Base type.
Мы однажды так _очень_ больно обожглись. В одной из задач надо было к каждому типу прикрутить гуид, ну и сделали static readonly поле TypeId.
Итог был немного предсказуем
Решарпер такие ошибки ловит, но решарпер есть не у всех, а другие инструменты статического анализа используются ещё реже.
Не, есть частные случаи, когда кровь из носу надо иметь одинаковые static-мемберы в разных типах, но для и решения частные, под все сценарии не подходят.
Чтоб не перечислять всё — можно пример, зачем именно оно понадобилось?
В Delphi есть виртуальные статические методы. Это метаклассы. Суть в том, что это синглетоны и они наследуются вместе с классом. Можно сэмулировать такое поведение в C# но вручную. http://rsdn.org/forum/philosophy/563970.flat
Здравствуйте, Sinix, Вы писали:
S>Чтоб не перечислять всё — можно пример, зачем именно оно понадобилось?
Ну короче есть у меня базовый абстрактный класс, пусть будет A. От которого наследуют ещё несколько классов, пусть будет В и C. У всех трёх классов должны быть несколько статических свойств, например Type и Name которые должно возвращать разный результат в зависимости от класса для которого вызываются. Надо именно так, т.к. периодически нужно получать значение этих свойств не создавая экземпляр класса, поскольку это не удобно и не нужно.
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Cynic, Вы писали:
S>В Delphi есть виртуальные статические методы. Это метаклассы. Суть в том, что это синглетоны и они наследуются вместе с классом. Можно сэмулировать такое поведение в C# но вручную. S>http://rsdn.org/forum/philosophy/563970.flat
Здравствуйте, Cynic, Вы писали:
C>Здравствуйте, Serginio1, Вы писали:
S>>Здравствуйте, Cynic, Вы писали:
S>>В Delphi есть виртуальные статические методы. Это метаклассы. Суть в том, что это синглетоны и они наследуются вместе с классом. Можно сэмулировать такое поведение в C# но вручную. S>>http://rsdn.org/forum/philosophy/563970.flat
C>Не понимаю, как меня это избавит от необходимости плодить статические методы с одинаковыми именами в производных классах
У обычного класса есть статическое поле с типом некого класса который будет сиглетоном и содержать нужные поля. Назовем его метаклассом. Ты будешь плодить только его, а в него прописывать наследника метакласса.
Этот метакласс может переопределть поля, добавлять новые.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>У обычного класса есть статическое поле с типом некого класса который будет сиглетоном и содержать нужные поля. Назовем его метаклассом. Ты будешь плодить только его, а в него прописывать наследника метакласса. S>Этот метакласс может переопределть поля, добавлять новые.
Здравствуйте, Cynic, Вы писали:
C>Есть у меня иерархия классов (два уровня), в которой все классы должны иметь статические члены с одинаковыми именами, но разным возвращаемым значением. Вопрос как это сделать? Унаследовать статические члены нельзя (все они будут ссылаться на базовый тип), а copy/paste кода меня как-то не вдохновляет. С другой стороны интерфейсы тут тоже не помогут, т.к. декларировать статические члены не могут. Шаблоны тут то-же не к месту, т.к. не чего передавать в параметра шаблона (<T>). Так что же делать то с этим господа? C>Попробую пояснить, что имею ввиду. Шла бы речь о не статических членах я бы сделал так: C>
C>class A
C>{
C> protected int field;
C> public A()
C> {
C> field = 1;
C> }
C> public int Field
C> {
C> get { return field; }
C> }
C>}
C>class B : A
C>{
C> public B()
C> {
C> field = 2;
C> }
C>}
C>...
C>var a = new A();
C>var b = new B();
C>Console.WriteLine(a.Field); // 1
C>Console.WriteLine(b.Field); // 2
C>
C>Хотелось бы нечто подобное сделать и со статическими версиями поля field и свойства Field.
А такой вариант не устроит:
public class A
{
public static object Foo=new object();
}
public class B : A
{
public static string Foo = "Foo";
}
Здравствуйте, Cynic, Вы писали:
C>Ну короче есть у меня базовый абстрактный класс, пусть будет A. ...
А, ну те же грабли, на которые мы наступили. Достаточно добавить наследника и не прописать в нём те же свойства, и использующий код легко может получить значения не для того типа.
Условно рабочих решений тут два:
* Закрытая иерархия типов: кодогенерация (T4) с автозапуском при каждой сборке. + (для большого проекта) тест, который перебирает всех наследников базового типа во всех сборках + проверяет наличие полей.
* Открытая иерархия типов: методы вида XxxHelpers.NameOf<TClass>() (с кэшированием значений в словаре, понятное дело). Плюс всё тот же тест. Как значение вытаскивать — на ваше усмотрение, самый простой способ — через атрибут
Здравствуйте, Qulac, Вы писали:
Q>А такой вариант не устроит: Q>
Q> public class A
Q> {
Q> public static object Foo=new object();
Q> }
Q> public class B : A
Q> {
Q> public static string Foo = "Foo"; // либо тип перепутали должен быть object, либо нужно дописать new
Q> }
Q>
Здравствуйте, Cynic, Вы писали:
C>Здравствуйте, Qulac, Вы писали:
Q>>А такой вариант не устроит: Q>>
Q>> public class A
Q>> {
Q>> public static object Foo=new object();
Q>> }
Q>> public class B : A
Q>> {
Q>> public static string Foo = "Foo"; // либо тип перепутали должен быть object, либо нужно дописать new
Q>> }
Q>>
C>И чё это Поле Foo в классах А и В всё равно одно.
Значения разные, хоть string хоть object, разве не это требуется?
Здравствуйте, Cynic, Вы писали:
C>Здравствуйте, Serginio1, Вы писали:
S>>У обычного класса есть статическое поле с типом некого класса который будет сиглетоном и содержать нужные поля. Назовем его метаклассом. Ты будешь плодить только его, а в него прописывать наследника метакласса. S>>Этот метакласс может переопределть поля, добавлять новые.
C>Опять не понимаю. Можно пример.
Но опять же проблема определения данных классов не определена и доступ к метаклассу из объекта идет через хэш таблицу, а по идее адрес метакласса должен быть прописан в VMT.
typeof и GetType из Net возвращает по сути тот же метакласс, но он вопервых не типизирован и только переопределяет виртуальные методы базового класса Type и нет возможности его расширения.
Для меня лично необходимость метаклассов не оспорима, но интересно как к этому относится программистское сообщество. И может лишний раз заострить внимание на этой проблеме разработчиков компиляторов и сред.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Cynic, Вы писали:
C>Ну короче есть у меня базовый абстрактный класс, пусть будет A. От которого наследуют ещё несколько классов, пусть будет В и C. У всех трёх классов должны быть несколько статических свойств, например Type и Name которые должно возвращать разный результат в зависимости от класса для которого вызываются. Надо именно так, т.к. периодически нужно получать значение этих свойств не создавая экземпляр класса, поскольку это не удобно и не нужно.
Здравствуйте, Cynic, Вы писали:
C>Есть у меня иерархия классов (два уровня), в которой все классы должны иметь статические члены с одинаковыми именами, но разным возвращаемым значением. Вопрос как это сделать? Унаследовать статические члены нельзя (все они будут ссылаться на базовый тип), а copy/paste кода меня как-то не вдохновляет. С другой стороны интерфейсы тут тоже не помогут, т.к. декларировать статические члены не могут. Шаблоны тут то-же не к месту, т.к. не чего передавать в параметра шаблона (<T>). Так что же делать то с этим господа? C>Попробую пояснить, что имею ввиду. Шла бы речь о не статических членах я бы сделал так:
C>Хотелось бы нечто подобное сделать и со статическими версиями поля field и свойства Field.
Типа такого ?
public class Props {
public string name;
}
public class PropsList {
Dictionary<Type,Props> db = new Dictionary<Type,Props>();
public PropsList add(Type type,Props props) {
db[type] = props;
return this;
}
public Props get(Type type) {
Props res;
if (!db.TryGetValue(type,out res))
throw new NullReferenceException();
return res;
}
}
public static class PropsExt {
static public PropsList traits = new PropsList();
public static Props static_props(this object a) {
return a is Type ? traits.get((Type)a) : traits.get(a.GetType());
}
}
class Example {
public class A { }
public class B : A {}
static Props static_props<T>(T t) { return t is Type ? PropsExt.traits.get(t as Type) : t.static_props(); }
static void Main(string[] args) {
PropsExt.traits = new PropsList()
.add(typeof(A),new Props() { name = "ordinary A" })
.add(typeof(B),new Props() { name = "The big B" });
A a = new A(), b = new B();
Console.WriteLine("a.static_props.name={0}",a.static_props().name);
Console.WriteLine("b.static_props.name={0}",b.static_props().name);
Console.WriteLine("t(A).name={0}",typeof(A).static_props().name);
Console.WriteLine("t(B).name={0}",typeof(B).static_props().name);
Console.WriteLine("static_props(a).name={0}",static_props(a).name);
Console.WriteLine("static_props(b).name={0}",static_props(b).name);
Console.WriteLine("static_props(A).name={0}",static_props(typeof(A)).name);
Console.WriteLine("static_props(B).name={0}",static_props(typeof(B)).name);
}
}