PropertyChanged for indexer property - c#

I have a class with an indexer property, with a string key:
public class IndexerProvider {
public object this[string key] {
get
{
return ...
}
set
{
...
}
}
...
}
I bind to an instance of this class in WPF, using indexer notation:
<TextBox Text="{Binding [IndexerKeyThingy]}">
That works fine, but I want to raise a PropertyChanged event when one of the indexer values changes. I tried raising it with a property name of "[keyname]" (i.e. including [] around the name of the key), but that doesn't seem to work. I don't get binding errors in my output window whatsoever.
I can't use CollectionChangedEvent, because the index is not integer based. And technically, the object isn't a collection anyway.
Can I do this, and so, how?

According to this blog entry, you have to use "Item[]". Item being the name of the property generated by the compiler when using an indexer.
If you want to be explicit, you can decorate the indexer property with an IndexerName attribute.
That would make the code look like:
public class IndexerProvider : INotifyPropertyChanged {
[IndexerName ("Item")]
public object this [string key] {
get {
return ...;
}
set {
... = value;
FirePropertyChanged ("Item[]");
}
}
}
At least it makes the intent more clear. I don't suggest you change the indexer name though, if your buddy found the string "Item[]" hard coded, it probably means that WPF would not be able to deal with a different indexer name.

Additionaly, you can use
FirePropertyChanged ("Item[IndexerKeyThingy]");
To notify only controls bound to IndexerKeyThingy on your indexer.

There are at least a couple of additional caveats when dealing with INotifyPropertyChang(ed/ing) and indexers.
The first is that most of the popular methods of avoiding magic property name strings are ineffective. The string created by the [CallerMemberName] attribute is missing the '[]' at the end, and lambda member expressions have problems expressing the concept at all.
() => this[] //Is invalid
() => this[i] //Is a method call expression on get_Item(TIndex i)
() => this //Is a constant expression on the base object
Several other posts have used Binding.IndexerName to avoid the string literal "Item[]", which is reasonable, but raises the second potential issue. An investigation of the dissasembly of related parts of WPF turned up the following segment in PropertyPath.ResolvePathParts.
if (this._arySVI[i].type == SourceValueType.Indexer)
{
IndexerParameterInfo[] array = this.ResolveIndexerParams(this._arySVI[i].paramList, obj, throwOnError);
this._earlyBoundPathParts[i] = array;
this._arySVI[i].propertyName = "Item[]";
}
The repeated use of "Item[]" as a constant value suggests that WPF is expecting that to be the name passed in the PropertyChanged event, and, even if it doesn't care what the actual property is called (which I didn't determine to my satisfaction one way or the other), avoiding use of [IndexerName] would maintain consistency.

Actually, I believe setting the IndexerName attribute to "Item" is redundant. The IndexerName attribute is specifically designed to rename an index, if you want to give it's collection item a different name. So your code could look something like this:
public class IndexerProvider : INotifyPropertyChanged {
[IndexerName("myIndexItem")]
public object this [string key] {
get {
return ...;
}
set {
... = value;
FirePropertyChanged ("myIndexItem[]");
}
}
}
Once you set the indexer name to whatever you want, you can then use it in the FirePropertyChanged event.

Related

Code brevity in C# - condensing a setter that throws if null

In prior versions of C#, if you wanted to prevent a null reference exception, you needed to build your setters defensively:
public Guid ItemId { get; set; } //foreign key, required
private Item _item;
public virtual Item Item {
get {
return _item;
}
set {
if(value == null) throw new ArgumentNullException(nameof(value));
_item = value;
ItemId = value.ItemId;
}
}
With more modern implementations, this can be condensed a certain amount using the null-coalescing operator and expression bodies:
private Item _item;
public virtual Item Item {
get => _item;
set => _item = value ?? throw new ArgumentNullException(nameof(value));
}
However, I am curious if this could not be condensed entirely down into a variation of the standard reference:
public virtual Item Item { get; set; }
Such that you do not have to define a private item.
Suggestions? Or is the second code block as efficient/simple as I can get?
I am looking for a solution within the current C# framework, not something I have to spend money on. Right now my use case proposition does not support a paid product
Disclaimer: Those are potential 'alternative' ways of filtering out invalid assignments into properties. This might not provide a straight answer to the question, but rather give ideas how to go on about doing it more generically without defining private properties and defining getters and setters explicitly.
Depending on what Item actually is, you could perhaps create a non-nullable type of Item by creating it as a struct.
Non nullable types are called structs. They are nothing new, they are value types which allow to store properties of type int, string, bool etc.
As on MSDN:
A struct type is a value type that is typically used to encapsulate
small groups of related variables, such as the coordinates of a
rectangle or the characteristics of an item in an inventory.
The following example shows a simple struct declaration:
public struct Book
{
public decimal price{ get; set;}
public string title;
public string author;
}
Reference
Edit (Struct should be sufficient if the object is supposed to be non-nullable type, however if we're talking properties of the class then read below.) :
Another way would be using OnPropertyChanged event which is part of the INotifyPropertyChanged interface.
While the event does not explicitly give you the value that has been changed to, you can grab it as it does provide you the property name. So you could run your validation post assignment and throw then, I suppose however it might not be the best option.
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var propertyValue = sender.GetType().GetProperty(e.PropertyName).GetValue(sender);
}
Another solution would be using DataAnnotations and add Required attributes on your properties. If I'm not mistaken they will not throw straight away, until you call your own validate function to validate the class, I guess, combined with the above method this would work pretty well and would be pretty generic. Once written you wouldn't have to write your getters and setters explicitly but rather attach just one event to your class and validate it once a property changes.
Here's a small example:
Your Item model for example...
public class Item
{
[Required]
public string Name { get; set; }
}
You would then implement a generic function which would validate all properties.
public bool TryValidate(object #object, out ICollection < ValidationResult > results) {
var context = new ValidationContext(#object, serviceProvider: null, items: null);
results = new List <ValidationResult> ();
return Validator.TryValidateObject(
#object, context, results,
validateAllProperties: true
);
}
Inside that function you would of course throw an exception if validation failed, your results array would contain properties that it failed on an default messages if I'm not mistaken. I believe this is a bit complex, but if you're looking for reducing the number of properties and setter implementations, this could be a step forward. I'm not sure on the overhead etc. Personally, I think on a larger scale, this would be super useful to validate models which are created on the fly from db data or any external source.
Validator Reference | Data Annotations Reference | ValidationResults Reference | PropertyChanged MSDN Sample

Taking multiple types in a property setter

I want to option to set a property with multiple types and am struggling to find a solution.
public static PropertyType Property
{
get { return Property;}
set {
if (value.GetType() == typeof(PropertyType))
{
Property = value;
}
//Or any other type
if (value.GetType() == typeof(string))
{
Property = FunctionThatReturnsPropertyType(value);
}
}
}
I hope that makes sense, I am only ever setting the Property as one type but I would like to be able to assign to it with other types and then transform them within the setter - is this possible?
What you want looks like design error.
In C# property's setter and getter have always the same type. So you have basically next choices:
Make your property type object (or dynamic if you want to get even worse design) and transform values within the setter as you stated in the question - i strongly recommend to avoid this approach.
Get away from property concept and create separate methods to get value of the field and assign from different types. This approach will allow you to assign value if you dont know the type at compile-time while getter-method will be typed still correctly. But generally it still looks like bad design.
Make all the transformations outside the property, This solution is preferred. You should know which type you will use in every separate case.
Try Property type as object.
public static Object PropertyName
{
get { return PropertyName; }
set { PropertyName = value; }
}

Using Getters and Setters in Unity

I have another question about this with getters and setters. Now that I started working with c# getters and setters as I understood them. The problem I see is that why should I make public variable that looks like this:
// Variable
private int _iRandomNumber
// Getter and setter
public int iRandomNumber
{
get { return _iRandomNumber; }
set { _iRandomNumber = value; }
}
I don't see the point of that since what different would it then be to just make the variable public since it's anyway got the get and set in the same bracket?
However if I do like this:
// Variable
private int _iRandomNumber
// Getter and setter
public int GetiRandomNumber { get { return _iRandomNumber; } }
public int SetiRandomNumber { set { _iRandomNumber = value; } }
Then when I try to use my SetiRandomNumber by itself Unity complier complains that I cannot use my SetProperty since I do not have a GET property inside my SET. Should I really have to make it like the first example I wrote because as I wrote then what's the point of Getters and Setters in c#?
Or should I instead move away from them, like I asked from the beginning and make functions for each Get and Set like in c++ so I can actually use them by themself?
Sorry for making this a new question, however it was not possible to add this as a comment in my previous question since it was to long.
Properties allow you to fire events when values are set, for instance:
public string Name {
get { return name; }
set {
name = value;
var eh = NameChanged; // avoid race condition.
if (eh != null)
eh(this, EventArgs.Empty);
}
}
private string name;
public event EventHandler NameChanged;
An added bonus is that you can track when your property gets set or read by putting breakpoints in the getter/setter with your debugger or diagnostic print statements.
I don't see the point of that since what different would it then be to just make the variable public since it's anyway got the get and set in the same bracket?
The difference is that you're separating your implementation detail (a field) from your API (the property). You could later change the implementation, e.g. to use one long variable to serve two int fields. (That's just one random example.) Or you can provide validation and change notification in the setter. Or you can perform lazy computation in the getter. Or you can make the property read-only from the outside, but writable privately. The list goes on.
Your second code declares two different properties - one read-only, and one write-only, both backed by the same variable. That's non-idiomatic C# to say the least, and gives no benefit. There's no linkage between those two properties, whereas in the first version there's a clear link between the getter and the setter as they're parts of the same property.
One thing to note is that your first example can be more concisely expressed with an automatically implemented property:
// Removed unconventional "i" prefix; this follows .NET naming conventions.
public int RandomNumber { get; set; }
That creates a private variable behind the scenes, and a public property whose getter and setter just use the private variable. Later if you want to change the implementation, you can do so without affecting the API.
The advantage of getters and setters is that they mainly act as functions so you can do something like this
private int _iRandomNumber;
public int iRandomNumber
{
get { return _iRandomNumber%10;} //you can do something like this mod function
set { _iRandomNumber = value+1000;} //you can manipulate the value being set
}
But if you do not have this kind of requirements on your variables, you might as well use just a public variable.

property change notification in generic property

Rephrased the question. Scroll down for the original
Ok, maybe I should have given you the whole picture. I have many classes which look like this:
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
}
There are also classes called Transform, Mesh, Collider, Appearance, etc. all derived from Component and all have nothing but properties which are declared as described above. What is important here is to invoke the ComponentChangedEvent. Everything works perfectly, but I was looking for a way where I don't have to rewrite the same logic for each property again and again.
I had a look here and liked the idea of using generic properties. What I came up with looks like this:
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 };
}
}
Then I would use it like this:
public class Movement : Component
{
public ComponentProperty<Vector3, Movement> LinearVelocity { get; set; }
public ComponentProperty<Vector3, Movement> AngularVelocity { get; set; }
}
But I am not able to get the instance where LinearVelocity comes from nor it's name as string. So my question was, if all of this is possible...
But it seems that I have no option other than keep doing it the way I was, writing this logic for each property manually.
Original Question:
Get instance of declaring class from property
I have a class with a property:
public class Foo
{
public int Bar { get; set; }
}
In another context I have something like this:
Foo fooInstance = new Foo();
DoSomething(fooInstance.Bar);
Then, in DoSomething I need to get fooInstance from having nothing but parameter. From the context, it is save to assume that not any integers are passed into DoSomething, but only public properties of ints.
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
}
Is that possible at all? Using reflection, or maybe a custom attribute on the property Bar?
Why do you want to send just a property to DoSomething, send it the whole object :), so it would become,
DoSomething(fooInstance);
Your function will then accept object instead of parameter. You can use an overload of this function to make sure that old code doesn't break.
There are several ways to deal with implementing INotifyPropertyChanged. You're doing almost the same thing, except you don't implement the interface and raise the event in a different way. But all of the solutions apply for you too.
Like you do, call a method with a string parameter: OnPropertyChanged("Property").
Call a method with a lambda that uses the property: OnPropertyChanged(() => Property). The advantage of this is that it's compile-time checked for typos and refactoring-friendly.
Use caller information to inject the name of the property: OnPropertyChanged(). This will work in C# 5.
Use something like Castle DynamicProxy to create a derived class at runtime that will call the method for you. This means you need to make your properties virtual and that you need to create instances of the class only through Castle.
Use an AOP framework to modify the code of your properties after compilation to call the method.
there's no way to get fooInstance from parameter. parameter is passed by value, and is only a copy of the value of fooInstance.Bar, it no longer has anything to do with fooInstance
That being said, the obvious solution is to write DoSomething like this
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
}
Property is just a field, which returns reference to some object on heap (i.e. its address). If property is not of reference type, it returns value of object.
So, when you do something like
DoSomething(fooInstance.Bar);
You just passing address of object Bar to method.
If Bar is reference type (i.e. class). Imagine that Mr.Foo has an address of Mr.Bar (462 for Marion County, Indiana). Mrs.CLR asks Mr.Foo for address of Mr.Bar. And then tells this address to somebody who needs address of Mr.Bar. How somebody will know, that CLR asked Foo about address of Bar? He received only an address 462 for Marion County, Indiana.
In case of value objects (int, double, structs etc), Mr.Foo has a cool mp3 track named Bar. Mrs. CLR creates a copy of that mp3 track and sends it to somebody. How somebody will know, that his mp3 track Bar is a copy of Mr.Foo's track?
So, if you want somebody to know about Mr.Foo, you need to pass an address of Mr.Foo to him:
DoSomething(fooInstance);
With this address somebody can visit Mr.Foo and ask him about address of Mr.Bar, or create a copy of his mp3 track :)

Auto-implemented properties and additional function

Is there a way to do something like this in C#:
public class Class2 {
public string PropertyName1 { get
{
return this; //i mean "PropertyName1"
}
set {
this = value;
DoAdditionalFunction();
}
}
Because I need to call additional function in the "set" I need to have an extra private field like
private string _propertyName1;
public string PropertyName1 { get
{
return _propertyName1;
}
set {
_propertyName1= value;
DoAdditionalFunction();
}
I don't want to use additional property like _propertyName1. Is there a way to accomplish this or any best practices?
No - if you need any behaviour other than the most trivial "set a field, return the field value", you need to write "full" properties. Automatically implemented properties are only a shorthand for trivial properties.
Note that you haven't really got an "extra" private field, in terms of the actual contents of an object - it's just that you're explicitly declaring the private field instead of letting the compiler do it for you as part of the automatically implemented property.
(It's not clear what your first property is trying to do - setting this in a class is invalid, and you can't return this from a property of type string unless you've got a conversion to string...)

Categories