2013-09-04 2 views
3

У меня есть один объект контекста, с которым я хочу иметь доступ из большого количества классов различий. У меня есть код, который выглядит какАльтернативы прохождению объекта контекста

Context ctx = new Context(); 
Section section = new Section(ctx) { 
    Data1 = new SomeData(ctx) { Value = 123 }, 
    Data2 = new SomeOtherData(ctx) { Foo = "bar" }, 
    SubSection = new Section(ctx) { 
     MoreData = new MoreData(ctx) { Text = "Hello!" } 
    } 
}; 

Но я бы очень хотел, это код, который выглядит следующим образом:

using(Context.New()) { 
    Section section = new Section() { 
     Data1 = new SomeData { Value = 123 }, 
     Data2 = new SomeOtherData { Foo = "bar" }, 
     SubSection = new Section { 
      MoreData = new MoreData { Text = "Hello!" } 
     } 
    }; 
    // do something with section 
} 

Возможно ли это? Я буду использовать его в ASP.NET, а также в .exes (и, вероятно, что-то еще в будущем), поэтому я не могу просто хранить static или где-то ссылаться на локальную ссылку.

Это не должно быть точно так же, как указано выше, только так, чтобы мне не пришлось передавать контекст каждому объекту, который я создаю. Я думал об использовании методов расширения, таких как context.createSomeData(), но для этого требуется больше шаблонов для каждого класса и на самом деле не лучше, поскольку вам все еще нужен объект контекста.

Идеально должен работать под VS2008/.NET3.5, хотя мне все равно будет интересно, если есть какой-либо способ сделать это вообще.

UPDATE: Я в конечном итоге решение этого рефакторинга мой подход в следующем:

Section section = new Section { 
    Data1 = new SomeData { Value = 123 }, 
    Data2 = new SomeOtherData { Foo = "bar" }, 
    SubSection = new Section { 
     MoreData = new MoreData { Text = "Hello!" } 
    } 
}; 
section.DoStuffWithContext(new Context()); 

Хотя он может не работать для всех, это то, что мне нужно здесь.

Я оставлю этот вопрос открытым, если кто-то придумает хорошее решение исходной проблемы.

+2

Будет ли 'новый раздел (ctx) {Data1 = new SomeData {...}, Data2 = new SomeOtherData {...}, ...}' быть достаточно хорошим? Если это так, вы можете изменить настройки свойств класса 'Section', чтобы передать контекст назначенным значениям. – hvd

+0

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

ответ

1

№ Нет никакой ясной возможности. Вы даже используете инициализаторы объектов (new Obj { ... }), поэтому вам нужно использовать оператор new (это делает невозможным использование статических методов/методов расширения ctx).

Единственное, что вы можете сделать:

SomeData MakeSomeData(this Context ctx, int value) 
{ 
    return new SomeData(ctx) { Value = value }; 
} 

и инициализации:

Context ctx = new Context(); 

Section section = new Section(ctx) { 
    Data1 = ctx.MakeSomeData(123), ... 

, но я не думаю, что вы должны получить что-нибудь

+0

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

2

Вы можете определить статический метод Context.RetreiveData(), но вам не нужно реализовывать какой-либо шаблонный код внутри самого метода.

Используя шаблон команды, каждый конкретный тип проекта может предоставить свою собственную реализацию для метода RetreiveData(). Проект ASP.NET может предоставить метод, который будет извлекать данные из сеанса. Исполняемый файл WinForm может предоставить метод, который будет извлекать данные из некоторой глобальной переменной. Еще один проект может предоставить метод для извлечения данных из БД.

+0

Это разрывает развязку и инкапсуляцию до такой степени, что мне не удобно в этом конкретном проекте. Данные .exe A и .dlls B и C, где A имеет ссылку на B и B, ссылаются на C - когда 'Context' определен в C, тогда нам нужно будет реализовать этот дополнительный код в A. Это может кажутся чересчур педантичными, но то, как мы используем и распространяем эти библиотеки, будет невозможно. Хорошая идея. –

0

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

public interface IContextConsumer { 
    Context Context { get; set; } 
} 

А ваш базовый класс имеет метод так:

protected void AddChild(IContextConsumer child) { 
    child.Context = this.Context; 
} 

Реализации собственности нужно будет всего:

private SomeData _data1; 
public SomeData Data1 { 
    get { return _data1; } 
    set { 
     _data1 = value; 
     AddChild(_data1); 
    } 
} 

Можно даже позволить контекст, который будет переназначен на корень, если вы сделали что-то вроде этого:

protected void AddChild(IContextConsumer child) { 
    Children.Add(child); 
    child.Context = this.Context; 
} 

protected void OnContextChanged() { 
    foreach (var child in Children) child.Context = this.Context; 
} 

Производные классы просто должны были бы назвать OnContextChanged в своих реализациях свойств Context.

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