2014-01-11 3 views
0

Возьмите этот код, например:Почему базовые конструкторы находятся в статическом контексте? Как справиться?

public class DisposeMe : IDisposable 
{ 
    public void Dispose() 
    { 
     Console.WriteLine("I'm disposed!"); 
    } 
} 

public class Base 
{ 
    private readonly Object _object; 

    public Base(Object obj) 
    { 
     _object = obj; 
    } 
} 

public class Derived : Base, IDisposable 
{ 
    public Derived() 
     : base(new DisposeMe()) 
    { 
    } 

    public void Dispose() 
    { 
     // Should dispose the object allocated in the constructor. 
    } 
} 

У меня есть такой код в реальной программе.

Что я на самом деле хотел бы сделать, это заменить new DisposeMe() в Derived конструктор, в метод, который будет создавать & вернуть его, но и сохранить его в поле в процессе, так что я мог распоряжаться его в Derived.Dispose.

Однако я не могу, потому что по какой-либо причине (вне меня) конструктор, к которому обратился base, является статическим. Зачем? Как я могу обойти это?

P.S. Я знаю, что я мог бы изменить Base, чтобы быть IDisposable, и пусть он проверяет, подан ли объект IDisposable каждый раз, когда он расположен сам. Я не заинтересован в этом. Это громоздко, неэффективно и, самое главное, тот, кто выделил объект, должен быть ответственным за его удаление (иначе я бы стрелял в ногу, убирая объект, который используется где-то еще).

+1

Где бы вы положить, что фабричный метод (тот, который должен создать 'IDisposable')? Можете ли вы представить пример кода, который демонстрирует ваше намерение? Обратите внимание, что вы не можете использовать метод * instance * 'Derived', поскольку ваш экземпляр * все еще строится *, когда вы вызываете конструктор' Derived'. –

+0

@MattiasBuelens О, я вижу проблему сейчас. Так что же такое решение? У меня должна быть ссылка для распоряжения. Нужно ли мне менять свой дизайн? если так во что-то вроде чего? – MasterMastic

+0

_ тот, кто выделил объект, должен быть ответственным .... Да, точно. И не должно нести ответственность за его хранение. У вас просто не должно быть этой проблемы. Считайте, что это сообщение: ваш основной дизайн испорчен. \ –

ответ

4

Вы могли бы добавить защищенному свойство только для чтения в Base поэтому вы можете получить к нему доступ от Derived.Dispose.

public class DisposeMe : IDisposable 
{ 
    public void Dispose() 
    { 
     Console.WriteLine("I'm disposed!"); 
    } 
} 

public class Base 
{ 
    private readonly Object _object; 
    protected Object _Object { get { return _object; } } 

    public Base(Object obj) 
    { 
     _object = obj; 
    } 
} 

public class Derived : Base, IDisposable 
{ 
    public Derived() 
     : base(new DisposeMe()) 
    { 
    } 

    public void Dispose() 
    { 
     (_Object as IDisposable).Dispose(); 
    } 
} 
+0

Испугался сделать это (я очень скрытный, когда речь идет о ООП), но другой вариант - сохранить одну и ту же ссылку дважды, одну для использования и одну для утилизации. Вы выигрываете судьбу; Спасибо, Эйфорик! – MasterMastic

+1

@Ken Я не думаю, что что-то не так, выставляя данные только для чтения в классе. Проблемы возникают, когда вы можете их изменить. – Euphoric

+0

О, я имею в виду, что меня отталкивает, просто защищает его. @Steve в самом деле, это гарантированно будет 'IDisposable', хотя я проверил его на null в фактическом проекте. Спасибо вам обоим. – MasterMastic

2

Я думаю, что самый простой способ это сделать завод для Derived класса:

public static Derived CreateDerived() 
{ 
    DisposeMe d = new DisposeMe(); 
    return new Derived(d); 
} 

private DisposeMe _d; 
private Derived(DisposeMe d) : base (d) 
{ 
    _d = d; 
} 

, а затем ваш метод Dispose:

public void Dispose() 
{ 
    _d.Dispose(); 
} 
+0

Если конструктор генерирует исключение, вы будете утечка 'new DisposeMe'. Я думаю, было бы лучше сделать что-то вроде 'Derived result = null; try {result = new DisposeMe (d); } finally {if (result == null) d.Dispose();} return result; '; слишком плохо, что для этого нет более приятной картины. – supercat

0
public class Derived<T> : Base, IDisposable where T : IDisposable, new() 
{ 
    public Derived() 
     : base(new T()) 
    { 
    } 

    public void Dispose() 
    { 
     var obj = base._object as IDisposable; 
     if (obj != null) 
      obj.Dispose(); 
    } 
} 
+0

'_object' не отображается' Derived'. Это 'частный'. Решенный принятый ответ позволяет сделать это, но спасибо. – MasterMastic

Смежные вопросы