Reputation: 2051
Consider the following example:
public class Foo
{
private string _text;
[BsonElement("text"), BsonRequired]
public string Text
{
get { return _text; }
set
{
_text = value;
Bar(_text);
}
}
private void Bar(string text)
{
//Only relevant when Text is set by the user of the class,
//not during deserialization
}
}
The setter of the Text
property and, subsequently, the method Bar
are called both when the user of the class assigns a new value to the property and during object deserialization by the MongoDB C# driver. What I need is to ensure that Bar
is called only when the Text
property is set by the user and not during deserialization.
I see two solutions which don't really suit me:
The first is to move the BsonElement
attribute to the backing field. However, as far as I know, the BsonElement
attribute is used in query building by the MongoDB C# driver, so I will lose the ability to use the Text
property in queries.
The second solution is to make the Text
setter private and add a method through which the user of the class will set the Text
property, and in which the Bar
method would be called. However, the Text
setter is used very often in the existing solution, and I'm a bit reluctant to change 70+ calls across all files. Plus, the code will become less readable.
Is there any cleaner way to separate deserialization and user-prompted property change while retaining the BsonElement
attribute on the property?
Upvotes: 2
Views: 12059
Reputation: 180
I know this question is old, but I'd still like to help for other people stumbling on this issue as I have done.
It basically boils down to something very simple: serialization and deserialization are not limited to public fields and properties!
The next example will cover the original question without having to invent dubious secondary properties:
public class Foo
{
[BsonElement("Text"), BsonRequired]
private string _text;
[BsonIgnore]
public string Text
{
get { return _text; }
set
{
_text = value;
Bar(_text);
}
}
private void Bar(string text)
{
//Only relevant when Text is set by the user of the class,
//not during deserialization
}
}
Simply put your BsonElement
class on the backing field and tell it to BsonIgnore
the property.
You can do whatever you like in the getter and setter without having to worry about deserialization which now occurs on private field level.
Hope this helps somebody!
Upvotes: 4
Reputation: 1497
Why not create a seperate property for the users and for the DB for the same private variable, something like this,
public class Foo
{
private string _text;
[BsonElement("text"), BsonRequired]
public string TextDB
{
get { return _text; }
set
{
_text = value;
}
}
[BsonIgnore]
public string Text
{
get { return _text; }
set
{
_text = value;
Bar(_text);
}
}
private void Bar(string text)
{
//Only relevant when Text is set by the user of the class,
//not during deserialization
}
}
Upvotes: 1
Reputation: 4094
You can use a little trick an implement a kind of property listener.
The usage would be:
// Working with some foo here...
var foo = new Foo();
foo.Text = "Won't fire anything";
using (var propertyListener = new FooPropertiesListener(foo))
{
foo.Text = "Something will fire you listener";
}
// Some more work with foo here...
foo.Text = "Won't fire anything";
And the implementation behind it, something like:
FooPropertiesListener
public class FooPropertiesListener : IDisposable
{
private readonly Foo Foo;
public FooPropertiesListener(Foo foo)
{
this.Foo = foo;
this.Foo.PropertiesListener = this;
}
public void Bar(string text)
{
//Only relevant when Text is set by the user of the class,
//not during deserialization
}
public void Dispose()
{
Foo.PropertiesListener = null;
}
}
Foo
public class Foo
{
internal FooPropertiesListener PropertiesListener;
private string _text;
[BsonElement("text"), BsonRequired]
public string Text
{
get { return _text; }
set
{
_text = value;
if (PropertiesListener != null)
{
PropertiesListener.Bar(_text);
}
}
}
}
Upvotes: 0