2012-02-09 3 views
-1

У меня есть разные производные объекты, которые я хотел бы, чтобы пользователь мог использовать инициализаторы объектов с. У меня есть свойство «Инициализация», которое я хочу быть истинным, поскольку эти поля устанавливаются, а затем я хочу, чтобы свойство Initializing было установлено на false после этого.Как сказать, когда инициализатор объекта сделан

Как узнать, когда инициализатор объекта сделан, чтобы это сделать?

class Foo 
{  
    Public Foo(string p1, string p2) 
    { 
     Initializing = true; 
     Property1 = p1; 
     Property2 = p2; 
     Initializing = false; 
    } 

    bool Initializing; 

    string _property1; 
    string Property1 
    { 
     get { return _property1; } 
     set { _property1 = value; DoSomething(); } 
    } 

    string Property2 { get; set; } 

    public void DoSomething() 
    { 
     if(Initializing) return; // Don't want to continue if initializing 
     // Do something here 
    } 
} 

В приведенном выше примере он отлично работает, если вы используете конструктор. Однако, как заставить его работать одинаково с инициализатором объекта.

EDIT: Для всех вас скептики, вот кто-то ищет именно то, что я после - http://blogs.clariusconsulting.net/kzu/how-to-make-object-initializers-more-useful/

К сожалению, это взгляд любит это невозможность хотя.

+0

Можете ли вы опубликовать некоторый код, чтобы лучше показать, что вы хотите сделать? –

+0

@AndrewCooper Там вы идете. –

+1

@BrandonMoore Это действительно плохая идея. Вы буквально заставили меня содрогнуться. – asawyer

ответ

4

Если вам действительно нужно отслеживать инициализацию вашего объекта, вам необходимо реализовать эту логику вручную. Один из подходов - скопировать то, что используется генератором кода WinForms. Где объекты выставляют интерфейс ISupportInitialize, когда они хотят обновлять свойства в пакете. Так что использование было бы что-то вроде ...

var x = new Foo(); 
x.BeginInit(); 
x.Property1 = 1; 
x.Property2 = 2; 
x.EndInit(); 
+0

+1 Для того, чтобы быть единственным конструктивным человеком здесь и размещать что-то полезное, даже если это не совсем помогает моей ситуации. Я думаю, мне просто нужно найти лучший подход, потому что то, что я хочу, в основном, относится к инициализатору объекта, как к конструктору, хотя я знаю, что это не то, что есть. –

+0

@BrandonMoore: Я тоже собирался ответить на этот вопрос. *** Так вы это делаете. *** Вы должны проверить и выбросить, если BeginInit/EndInit не были вызваны или не были вызваны в правильном порядке. Единственная альтернатива - предоставить ctor, который принимает тип, который содержит все данные, необходимые для инициализации вашего типа. Это еще один шаблон, найденный в структуре (проверьте AppDomain как пример). Это ответ, поэтому вам больше не нужно ничего спрашивать, кроме нового вопроса. – Will

+0

@ С благодарностью. Очевидно, не то, что я надеялся услышать, но это то, что это:/ –

1

Этот вопрос не имеет смысла. Синтаксис инициализатора объекта - это просто синтаксическая сокращенность сахара.

Это:

var myInstance = new someClass() 
{ 
    Prop1 = "", 
    Prop2 = "", 
    Prop3 = "", 
    Prop4 = "", 
    Prop5 = "" 
} 

точно так же, как это:

var myInstance = new someClass(); 
myInstance.Prop1 = ""; 
myInstance.Prop2 = ""; 
myInstance.Prop3 = ""; 
myInstance.Prop4 = ""; 
myInstance.Prop5 = ""; 

Там нет "Готово", чтобы быть обнаруженным.

То, что вы хотите, чтобы можно было сделано, мы что-то вроде:

class someClass() 
{ 
    public string AStringProperty { get; set; } 
    public bool IsInitiazlied 
    { 
    return string.IsNullOrWhitespace(this.AStringProperty); 
    } 
} 

Или, сделать т е р взять щёток состояние значений, то ваш Гарантируется быть настройки.

class someClass() 
{ 
    public string AStringProperty { get; set; } 
    public someClass(string AStringPropertyInit) 
    { 
     this.AStringProperty = AStringPropertyInit; 
    } 
} 

РЕДАКТИРОВАТЬ

class Foo 
{  
    Public Foo(string p1, string p2) 
    { 

     _property1= p1; //set the backing store directly, 
         //skips the side effect in the setter 
     Property2 = p2; 

     DoSomething(); // now cause the side effect 
         // we know everything is setup 
    } 



    string _property1; 
    string Property1 
    { 
     get { return _property1; } 
     set { _property1 = value; DoSomething(); } 
    } 

    string Property2 { get; set; } 

    public void DoSomething() 
    { 
     // Do something here 
    } 
} 
+0

Термин «синтаксический сахар»;) –

+0

@Jeff Поздно. >< – asawyer

+0

@asawyer Спасибо за помощь. Я не хочу, чтобы материал в DoSomething() запускался, если свойства заданы из инициализатора, но я делаю, если они не вызываются из инициализатора. Идея заключается в том, что когда я инициализирую объект, он находится в «начальном» состоянии. Но когда свойства меняются, я действительно хочу, чтобы DoSomething() запускался. Таким образом, это решение еще не совсем решает эту проблему. –

0

Объект intializer находится в нескольких минутах рукой для создания объекта и установки кучу свойств на нем. Не имеет смысла спрашивать «когда он завершен».

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

Update

Просто читать ваши комментарии на ответ @ asawyer в. Невозможно определить, установлено ли свойство в инициализаторе или нет. Просто для иллюстрации - вот три фрагмента кода, которые делают точно то же самое, за исключением того, что вам, похоже, требуется дефферентное поведение для каждого.

var someVar1 = new SomeClass() 
       { 
        Prop1 = "value1"; 
        Prop2 = "value2"; 
       }; 

var someVar2 = new SomeClass() 
       { 
        Prop1 = "value1"; 
       }; 
someVar2.Prop2 = "value2"; 

var someVar3 = new SomeClass(); 
someVar3.Prop1 = "value1"; 
someVar3.Prop2 = "value2"; 

Это не было бы трудно отслеживать выполнение отдельных инкубационных свойств и вызвать некоторые побочный эффект на всех, кроме первого исполнения, но сказать, что я только хочу, чтобы вызвать побочный эффект, если изменения клиента первоначальная конфигурация объекта не имеет смысла после завершения работы ctor.

+0

Не приравнивайте ограничение с логикой. Просто потому, что что-то не может быть сделано, не означает, что не имеет смысла делать это, если можно. –

+0

@BrandonMoore Дело в том, что в C# и, вероятно, в большинстве языков OO начальное состояние объекта - это то, что у вас есть после завершения конструктора. Как уже было сказано, инициализатор объекта представляет собой просто синтаксический сахар для настройки набора свойств. То же самое можно сделать с помощью конструктора по умолчанию и явных вызовов свойств. Если вы хотите заставить пользователя вашего класса задавать определенный набор свойств до того, как объект считается инициализированным, тогда вам лучше кодировать его в конструкторе и не иметь конструктор по умолчанию. –

1

Поскольку инициализация объекта - это просто синтаксический сахар, вы не можете отличить его от нормальных наборов свойств. Я также не могу думать о разумном случае, когда вы хотите относиться к ним по-разному.

Если вы говорите, что должно быть задано хотя бы 1 из свойств x (будь то синтаксис longhand или shorthand), вы можете установить инициализацию в true в ctor, а затем установить его false для каждого набора свойств ,

3

Нет смысла устанавливать флаги. Вы не можете получить доступ к объекту до тех пор, пока не будут запущены инициализаторы. Например:

var object = new object() { Prop1 = "Boo" } 

Поскольку ссылка, возвращенная из нового не может быть доступна только после prop1 установлен, нет никакого способа, чтобы получить доступ к любому из свойств, таким образом, нет контроля доступа нужно или беспокоиться о том, является ли он или ISN» t "done".

Хотя, я полагаю, я могу видеть, как вы могли бы иметь что-то вроде этого:

public class Foo { 
    private int _value; 
    public int Bar { 
     set { 
      _value = value * Baz; // don't want to do this if initializing 
     } 
    } 

    public int Baz { get; set; } 
} 

Если это то, что вас беспокоит, то вы разрабатываете свои объекты неправильно. Свойства не должны иметь побочных эффектов. Невозможно узнать, было ли сделано все намеки.

1

Вместо того, чтобы в зависимости от явной собственности, чтобы сказать вам, когда ваш объект инициализируется, вы могли бы иметь свой метод DoSomething подтвердить, что он имеет информацию, необходимую для выполнения работы ,Ваш пример довольно сырой, и я ожидаю ваша реальная реализация является более сложной, так что я просто буду считать, что Property1 и Property2 должны быть назначены того (означающего просто не пустая строку перед продолжением):

class Foo 
{  
    public Foo(string p1, string p2) 
    { 
     Property1 = p1; 
     Property2 = p2; 
    } 

    string Property1 { get; set; } 
    string Property2 { get; set; } 

    public void DoSomething() 
    { 
     // *** Replace this with something valid to your real code 
     if(!string.IsNullOrEmpty(Property1) || !string.IsNullOrEmpty(Property2)) 
      return; // Don't want to continue if not initialized 
     // Do something here 
    } 
} 

UPDATE

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

class Foo 
{ 
    public void DoSomething(FooConfig config) 
    { 
    } 
} 

ИЛИ

class Foo 
{ 
    private FooConfig config_; 

    public Foo(FooConfig config) 
    { 
     config_ = config; 
    } 

    public void DoSomething() 
    { 
    } 
} 

Где FooConfig определяется:

class FooConfig 
{ 
    public string Property1 { get; set; } 
    public string Property2 { get; set; } 
} 

И DoSomething вызывается с помощью:

(new Foo()).DoSomething(new FooConfig() { Property1 = "abc"; Property2 = "def"; }); 

ИЛИ

(new Foo(new FooConfig() { Property1 = "abc"; Property2 = "def"; })).DoSomething(); 

Это можно легко изменить, чтобы использовать конструктор на Foo или FooConfig.

+0

Дело в том, что я хочу, чтобы DoSomething запускался, если свойство было «Изменено». Но если объект был инициализирован с помощью свойства, я не хочу запускать DoSomething. –

+0

@BrandonMoore - Это немного запутанно. Таким образом, вы хотите, чтобы «DoSomething» выполнялось, если свойство имеет значение, если оно явно не задано методом 'set' свойства? –

+0

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