2012-04-20 2 views
0

Перефразируйте вопрос. Прокрутка вниз для оригиналаУведомление об изменении недвижимости в общем имуществе

Хорошо, возможно, я должен был дать вам всю картину. У меня есть много классов, которые выглядят следующим образом:

public class Movement : Component 
{ 
    private Vector3 linearVelocity; 
    public Vector3 LinearVelocity 
    { 
     get 
     { 
      return linearVelocity; 
     } 
     set 
     { 
      if (value != linearVelocity) 
      { 
       linearVelocity = value; 
       ComponentChangedEvent<Movement>.Invoke(this, "LinearVelocity"); 
      } 
     } 
    } 

    // other properties (e.g. AngularVelocity), which are declared exactly 
    // the same way as above 
} 

Есть также классы называются Transform, Mesh, коллайдер, внешний вид и т.д. все полученные от Component и вообще не имеют ничего, кроме свойств, которые объявлены, как описано выше. Здесь важно вызвать ComponentChangedEvent. Все работает отлично, но я искал способ, которым я не должен переписывать одну и ту же логику для каждого свойства снова и снова.

Я посмотрел here и мне понравилась идея использования общих свойств. То, что я придумал выглядит следующим образом:

public class ComponentProperty<TValue, TOwner> 
{ 
    private TValue _value; 

    public TValue Value 
    { 
     get 
     { 
      return _value; 
     } 
     set 
     { 
      if (!EqualityComparer<TValue>.Default.Equals(_value, value)) 
      { 
       _value = value; 
       ComponentChangedEvent<TOwner>.Invoke(
        /*get instance of the class which declares value (e.g. Movement instance)*/, 
        /*get name of property where value comes from (e.g. "LinearVelocity") */); 
      } 
     } 
    } 

    public static implicit operator TValue(ComponentProperty<TValue, TOwner> value) 
    { 
     return value.Value; 
    } 

    public static implicit operator ComponentProperty<TValue, TOwner>(TValue value) 
    { 
     return new ComponentProperty<TValue, TOwner> { Value = value }; 
    } 
} 

Тогда я хотел бы использовать его как это:

public class Movement : Component 
{ 
    public ComponentProperty<Vector3, Movement> LinearVelocity { get; set; } 
    public ComponentProperty<Vector3, Movement> AngularVelocity { get; set; } 
} 

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

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

Оригинал Вопрос:

Получить экземпляр объявляющего класса от собственности

У меня есть класс со свойством:

public class Foo 
{ 
    public int Bar { get; set; } 
} 

В другом контексте у меня есть что-то вроде этого:

Foo fooInstance = new Foo(); 
DoSomething(fooInstance.Bar); 

Затем, в DoSomething Мне нужно получить fooInstance от ничего, кроме parameter. Из контекста следует сохранить, что никакие целые числа не передаются в DoSomething, а только общедоступные свойства int.

public void DoSomething(int parameter) 
{ 
    // need to use fooInstance here as well, 
    // and no, it is not possible to just pass it in as another parameter 
} 

Возможно ли это вообще? Использование отражения или, может быть, настраиваемый атрибут свойства Bar?

+4

Вам нужно будет пересмотреть свой дизайн. Это невозможно. – BrokenGlass

+0

Я не понимаю, о чем вы просите ... Почему вы не можете дать «Foo» в качестве аргумента? – log0

+0

Почему вы не можете передать его в качестве другого параметра? –

ответ

2

Существует несколько способов решения проблемы с использованием INotifyPropertyChanged. Вы делаете почти то же самое, за исключением того, что вы не реализуете интерфейс и не поднимаете событие по-другому. Но все решения применяются и к вам.

  1. Как и вы, вызовите метод со строковым параметром: OnPropertyChanged("Property").
  2. Вызвать метод с помощью лямбда, который использует это свойство: OnPropertyChanged(() => Property). Преимущество этого заключается в том, что он проверяет время компиляции на опечатки и рефакторинг.
  3. Используйте caller information, чтобы ввести название объекта: OnPropertyChanged(). Это будет работать в C# 5.
  4. Используйте что-то вроде Castle DynamicProxy для создания производного класса во время выполнения, который вызовет этот метод для вас. Это означает, что вам нужно сделать свои свойства virtual и что вам нужно создавать экземпляры класса только через Castle.
  5. Используйте структуру AOP, чтобы изменить код своих свойств после компиляции, чтобы вызвать метод.
+0

Спасибо, я посмотрю на них. Внедрение INotifyPropertyChanged должно также сделать трюк. Информация о вызывающем абоненте (и другие материалы C# 5) выглядит интересной, но это на будущее. – christoph

0

нет способа получить fooInstance от parameter.parameter передается по значению, а только копия значения fooInstance.Bar, он больше не имеет ничего общего с fooInstance

Это, как говорится, очевидное решение написать DoSomething как это

public void DoSomething(Foo parameter) 
{ 
    // need to use fooInstance here as well, 
    // and no, it is not possible to just pass it in as another parameter 
} 
3

Почему вы хотите, чтобы отправить только свойство DoSomething, отправить его весь объект :), так что он стал бы,

DoSomething(fooInstance); 

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

0

Свойство - это просто поле, которое возвращает ссылку на некоторый объект на кучу (т. Е. Его адрес). Если свойство не относится к ссылочному типу, оно возвращает значение объекта.

Так что, когда вы делаете что-то вроде

DoSomething(fooInstance.Bar); 

Вы просто проездом адрес объекта Bar методу.

If Bar - ссылочный тип (то есть класс). Представьте, что Mr.Foo имеет адрес г-на Бар (462 для округа Мэрион, штат Индиана,). МиссисCLR просит г-на Фоу обратиться к г-ну Бар. А затем рассказывает этот адрес кому-то, кому нужен адрес г-на Бар. Как кто-то узнает, что CLR спросил Фу о адресе Bar? Он получил только адрес 462 для округа Мэрион, штат Индиана.

В случае значений объектов (int, double, structs и т. Д.), Mr.Foo имеет классный mp3-трек под названием Bar. Mrs. CLR создает копию этого mp3-трека и отправляет его кому-то. Как кто-нибудь узнает, что его mp3-трек Bar является копией трека Mr.Foo?

Так что, если вы хотите кого-то знать о Mr.Foo, вам нужно передать адрес Mr.Foo ему:

DoSomething(fooInstance); 

С помощью этого адреса кто-то может посетить Mr.Foo и спросить его о адрес г-на Бар или создать копию его mp3-трека :)

+0

Фактически параметр больше похож на функцию; есть геттер и сеттер, чтобы вернуть/установить локальное значение для свойства. Если это свойство было для ссылочного типа, оно просто передало бы новую ссылку для объекта, и эта ссылка была бы связана с одним и тем же объектом в памяти. Поскольку это тип значения, он передаст вам новую копию значения. –

+0

@ShawnL, я знаю, что на самом деле это свойство get_Name и set_Name :) Просто хотел упростить –

+0

Спасибо lazyberezovsky, красочное объяснение :) – christoph

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