Можете ли вы получить доступ к конкретному классу из абстрактного класса? - PullRequest
0 голосов
/ 10 марта 2011

У меня есть абстрактный класс, который представляет неизменное значение.Как и строки, в неизменяемом классе есть методы, которые изменяют экземпляр, но на самом деле просто возвращают новый экземпляр с изменениями.Абстрактный класс имеет некоторые из этих методов, которые имеют поведение по умолчанию.Могу ли я иметь такой вид Создать измененный экземпляр и вернуть логику в абстрактный класс?Я вешаю трубку, потому что я не знаю, что положить в ???позиции.Кажется, мне нужен тип T, представляющий производный тип.Существуют ли какие-либо подобные схемы для преодоления этой проблемы?

public abstract class BaseImmutable
{
    public readonly object Value;

    protected BaseImmutable(object val)
    {
        Value = val;
    }

    public ??? ModifiyButNotReally()
    {
        object newValue = GetNewObjectFromOld(Value);
        return new ???(newValue);
    }
}

public class DerivedImmutable : BaseImmutable
{
    public DerivedImmutable(object val) : base(val)
    {
    }
}

ОТВЕТ

Это оказалось проще, чем я подозревал.Метод можно сделать универсальным, не делая класс универсальным.Имея это в виду, единственное, что нам нужно сделать, - это ограничить универсальный аргумент для наследования от базового класса и требовать, чтобы он не был абстрактным путем включения ограничения new ().Последний шаг, который мне нужно было сделать, - это использовать отражение, чтобы получить конструктор без параметров для создания нового экземпляра.Я обнаружил, что это решение лучше, чем общий ответ класса, предложенный @Jason, который, как я узнал, известен как CURLYURURRING Template Pattern .Это также избавляет от необходимости создавать сложный для тестирования метод расширения / moq в отдельном статическом классе, как это предлагается @bottleneck.Тем не менее, ответ @ bottleneck - это то, что дало мне вдохновение для решения, поэтому баллы достаются ему.

public abstract class BaseImmutable
{
    public readonly object Value;

    protected BaseImmutable(object val)
    {
        Value = val;
    }

    public T ModifiyButNotReally<T>() where T : BaseImmutable, new()
    {
        object newValue = GetNewObjectFromOld(Value);
        var ctor = typeof(T).GetConstructor(new[] { typeof(object) });
        return (T)ctor.Invoke(new object[] { newValue });
    }
}

public class DerivedImmutable : BaseImmutable
{
    public DerivedImmutable(object val) : base(val)
    {
    }
}

Ответы [ 3 ]

3 голосов
/ 10 марта 2011

Может быть, метод расширения будет в порядке здесь?

public static T Modify<T>(this T immutable) where T:BaseImmutable{
    //work your magic here
    //return T something
}
3 голосов
/ 10 марта 2011

Вы могли бы сделать это:

abstract class BaseImmutable<T> {
    // ... 
    public T ModifiedButNotReally() { // ... }
}

class DerivedImmutable : BaseImmutable<DerivedImmutable> { // ... }

, где я выбрал массу деталей.

Тем не менее, это пахнет немного плохо.По сути, я даю вам механизм для решения вашей проблемы, мне просто не ясно, что то, что вы моделируете, лучше всего моделируется имеющейся у вас установкой.

2 голосов
/ 10 марта 2011

Подход Джейсона, вероятно, лучший вариант, который у вас есть. Вам нужно будет добавить тест типа времени выполнения (небезопасное приведение) к целевому типу, потому что система типов C # недостаточно выразительна для этого, но она будет работать.

Чтобы добавить немного фона - то, что вы просите, называется self types . Это возможность ссылаться на тип текущего экземпляра в объявлении типа. Это доступно на некоторых языках - например, Scala , но, к сожалению, не в C #. В вымышленном C # с self types вы можете объявить виртуальный метод, подобный этому:

public abstract class BaseImmutable {
  public abstract self GetNewObjectFromOld();
}

Класс Foo, реализующий метод, должен вернуть Foo в качестве результата. Чтобы найти больше информации и обходных путей, вы можете попробовать поискать различные подходы для эмуляции типов в C #.

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