I have various complex objects that often have collections of other complex objects. Sometimes I only want to load the collections when they're needed so I need a way to keep track of whether a collection has been loaded (null/empty doesn't necessarily mean it hasn't been loaded). To do this, these complex objects inherit from a class that maintains a collection of loaded collections. Then we just need to add a call to a function in the setter for each collection that we want to be tracked like so:
public List<ObjectA> ObjectAList {
get { return _objectAList; }
set {
_objectAList = value;
PropertyLoaded("ObjectAList");
}
}
The PropertyLoaded function updates a collection that keeps track of which collections have been loaded.
Unfortunately these objects get used in a webservice and so are (de)serialized and all setters are called and PropertyLoaded gets called when it actually hasn't been.
Ideally I'd like to be able to use OnSerializing/OnSerialized so the function knows if its being called legitimately however we use XmlSerializer so this doesn't work. As much as I'd like to change to using DataContractSerializer, for various reasons I can't do that at the moment.
Is there some other way to know if serialization is happening or not? If not or alternatively is there a better way to achieve the above without having to extra code each time a new collection needs to be tracked?
XmlSerializer does not support serialization callbacks. You have some options, though. For example, if you want to choose whether to serialize a property called ObjectAList, you can add a method:
public bool ShouldSerializeObjectAList () { /* logic */ }
If you need to know during deserialization too, you can use:
[XmlIgnore]
public bool ObjectAListSpecified {
get { /* logic whether to include it in serialization */ }
set { /* logic to apply during deserialization */ }
}
(although you might find - I can't be sure - that the set is only called for the true case)
The other option, of course, is to implement IXmlSerializable, but that should only be done as a last resort. It isn't fun.
Related
I have an Object:
public class BindObjectToFile
{
public int Property1 {get; set;}
public int Property2 {get; set;}
public BindObjectToFile(string BindingFilePath)
{
...
}
}
I have a Json File:
{
"Property1" : 1,
"Property2" : 2,
}
Whenever a property on the Object Changes, I want the Json File to change with it.
Whenever a property in the JsonFile Changes, I want the Object to change with it.
I'd like all children of BindObjectToFile to easily inherit this functionality, without requiring adjustments to the getters/setters on their properties.
Essentially, I want an object that feels like it is stored in a file, not in memory.
What I've Tried:
I started by (stupidly) Serializing/Deserializing the entire object on every single getter/setter in the object:
internal int _property1;
public int Property1
{
get
{
return JsonConvert.DeserializeObject<ObjectToFile>(File.ReadAllText(JsonFilePath))._property1;
}
set
{
_property1 = value;
File.WriteAllText(JsonFilePath, JsonConvert.SerializeObject(this));
}
}
Newtonsoft.json is great, But this approach seems wrong because it forces me to rewrite all of that boiler plate for each property on each new child without communicating to anyone that that is how my BindObjectToFile class is supposed to be used.
Next, I tried implementingINotifyPropertyChanged to only save the newly serialized object when a property changes. This was a little better, but it still doesn't account for situations where the file is changed by something other than this instance of 'BindObjectToFile'.
I tried Creating a Generic BindObjectToFile which also implemented INotifyPropertyChanged. I did this in hopes that by using a Generic object, I could get around this problem without using inheritance, so that I wouldn't need to find a way to force children to write crazy getters/setters for each of their properties:
public abstract class ObjectToFile<T> : INotifyPropertyChanged
{
public T _value;
public T Value
{
get
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText(Path));
}
set
{
_value = value;
File.WriteAllText(Path, JsonConvert.SerializeObject(_value ));
}
}
public string JsonFilePath;
public ObjectToFile(T value, string path)
{
_value = value;
JsonFilePath = path;
}
}
But, this still forces me to either raise or manage PropertyChange events in the child classes when their properties change.
And I don't want to do any of that--I Just want a fix-the-problem parent class so that I can happily create child classes that behave correctly without me needing to think about any of this.
That seems reasonable, right?
Caveats:
I don't mind rewriting/rereading the entire file every time a property is accessed or changed.
In my context, I don't care much about speed. If someone else opens up one of these files and I have to wait a few hundred ms for my turn, that's not a problem.
All the objects that I'm working with are extremely simple, containing properties with basic data types.
All the objects that I'm working with are extremely small, and rarely have more than five or six properties.
Thanks, All!
I don't believe you can only change part of a json file, to only save the property value that was changed. If the length of value changed, it would have to move the rest of the file up or down and I don't think you can do that. So you will have to rewrite the entire file every time. Which really sucks if some code changes more than one property at a time. I would probably add a .Save method or maybe even add change tracking with a .Commit when done making changes - so the file is written once per set of changes. This also helps to communicate to anyone using the class that that is how the object is to be used.
You also shouldn't be reading/deserializing the file every time a property is referenced. I would instead try using the FileSystemWatcher class (setting the Filter property) to be notified of changes to the file.
If the number of consumers watching the same file is an issue, perhaps look into using a document/nosql database instead of manually doing it yourself.
I have a class property that looks as follows:
public List<Recipe> RecipeList
{
get { return this._recipeList; }
set
{
this._recipeList = value;
OnPropertyChanged("RecipeList");
}
}
In another method I have the following which references the property above.
private void RecipeSearch()
{
this.RecipeList = RecipeManagerService.SearchByUnit(SearchCriteria)
.Where(recipe => recipe.IsApproved == true && !recipe.IsHidden).ToList();
}
Code Analysis is issuing a CA 2227 warning: Change RecipeList to be read-only by removing the setter. Could anyone tell me why?
Adding a public setter on a List<T> object is dangerous. You can eliminate this warning by making your setter private:
public List<Recipe> RecipeList
{
get { return this._recipeList; }
private set
{
this._recipeList = value;
OnPropertyChanged("RecipeList");
}
}
This will still allow your class to change this method, but no external source.
I think it's suggesting that usually collection properties themselves shouldn't be mutable - it's more common for the collection to be mutable, and just available via a setter.
It's only a suggestion though :)
In this case you'd use:
RecipeList.Clear();
RecipeList.AddRange(RecipeManagerService
.SearchByUnit(SearchCriteria)
.Where(r => r.IsApproved && !r.IsHidden));
Note that this won't fire the change event though... you might want to use ObservableCollection instead.
This will also mean that anyone can change the contents of the recipe list... do you definitely want that? Another alternative is to expose a ReadOnlyCollection<T> property or something like that, and only make changes within your own class. It really depends what you're trying to do though.
Do you want another instance messing with RecipeList? Generally, I don't let anything change my collection instances except the instance that owns the collection. You could make it private.
The MSDN description is fairly clear:
A writable collection property allows
a user to replace the collection with
a completely different collection
It wouldn't be good OO if the client of your class could change the list to be a completely different list of Recipes. That is against encapsulation.
Ensuring the clients just add or remove items is what you probably want to do.
I don't think there's anything illegal about the code, but it's common practice to have no public setter for collection type properties. Your private RecipeSearch method should just set _recipeList and raise the event, or you could make _recipeList itself a protected property that handles the event.
Allowing the list property to be mutated in two ways (via it's own Add and Remove methods and the list instance as a whole) creates an ambiguous interface to those who consume that property. This confuses responsibilities and creates a larger technical debt/maintenance overhead.
Instead, it is often better practise to separate these concerns so that the property provides access to a single instance of the list. If the list instance must be changeable, a separate mechanism for doing so makes it much clearer that the action of interacting with the property and the action of changing which list instance that property points to are distinct.
I am building a library to automatically create forms for Objects in the project that I am working on.
The codebase is in C#, and essentially we have a HUGE number of different objects to store information about different things. If I send these objects to the client side as JSON, it is easy enough to programatically inspect them to generate a form for all of the properties.
The problem is that I want to be able to create a simple way of enforcing permissions and doing validation on the client side. It needs to be done on a field by field level.
In javascript I would do this by creating a parallel object structure, which had some sort of { permissions : "someLevel", validator : someFunction } object at the nodes. With empty nodes implying free permissions and universal validation. This would let me simply iterate over the new object and the permissions object, run the check, and deal with the result.
Because I am overfamilar with the hammer that is javascript, this is really the only way that I can see to deal with this problem. My first implementation thus uses reflection to let me treat objects as dictionaries, that can be programatically iterated over, and then I just have dictionaries of dictionaries of PermissionRule objects which can be compared with.
Very javascripty. Very awkward.
Is there some better way that I can do this? Essentially a way to associate a data set with each property, and then iterate over those properties.
Or else am I Doing It Wrong?
It sounds like you are describing custom attributes - i.e.
[Permissions("someLevel"), Validator("someFunction")]
public string Foo {get;set;}
This requires some reflection to read the attributes, but is quite a nice way of decorating types / members / etc. You might also look at the pre-rolled [PrincipalPermission] for security checks. Is this what you mean?
Note the above would require:
public class PermissionsAttribute : Attribute {
private readonly string permissions;
public string Permissions { get {return permissions;}}
public PermissionsAttribute(string permissions) {
this.permissions = permissions;
}
}
(and similar for the other)
You can read them out with Attribute.GetCustomAttributes
I was wondering what is the recommended way to expose a collection within a class and if it is any different from the way of doing that same thing when working with NHibernate entities.
Let me explain... I never had a specific problem with my classes exposing collection properties like:
IList<SomeObjType> MyProperty { get; set; }
Having the setter as protected or private gives me some times a bit more control on how I want to handle the collection.
I recently came across this article by Davy Brion:
http://davybrion.com/blog/2009/10/stop-exposing-collections-already/
Davy, clearly recommends to have collections as IEnumerables instead of lets say Lists in order to disallow users of having the option to directly manipulate the contents of those collections. I can understand his point but I am not entirely convinced and by reading the comments on his post I am not the only one.
When it comes to NHibernate entities though, it makes much sense to hide the collections in the way he proposes especially when cascades are in place. I want to have complete control of an entity that is in session and its collections, and exposing AddXxx and RemoveXxx for collection properties makes much more sense to me.
The problem is how to do it?
If I have the entity's collections as IEnumerables I have no way of adding/removing elements to them without converting them to Lists by doing ToList() which makes a new list and therefore nothing can be persisted, or casting them to Lists which is a pain because of proxies and lazy loading.
The overall idea is to not allow an entity to be retrieved and have its collections manipulated (add.remove elements) directly but only through the methods I expose while honouring the cascades for collection persistence.
Your advice and ideas will be much appreciated.
How about...
private IList<string> _mappedProperty;
public IEnumerable<string> ExposedProperty
{
get { return _mappedProperty.AsEnumerable<string>(); }
}
public void Add(string value)
{
// Apply business rules, raise events, queue message, etc.
_mappedProperty.Add(value);
}
This solution is possible if you use NHibernate to map to the private field, ie. _mappedProperty. You can read more about how to do this in the access and naming strategies documentation here.
In fact, I prefer to map all my classes like this. Its better that the developer decides how to define the public interface of the class, not the ORM.
How about exposing them as ReadOnlyCollection?
IList<SomeObjType> _mappedProperty;
return new ReadOnlyCollection<SomeObjType> ExposedProperty
{
get
{
return new ReadOnlyCollection(_mappedProperty);
}
}
I am using NHibernate and I usually keep the collections as ISet and make the setter protected.
ISet<SomeObjType> MyProperty { get; protected set; }
I also provide the AddXxx and RemoveXxx for collection properties where they are required. This has worked quite satisfactorily for me most of the time. But I will say that there have been instances where it had made sense to allow client code add items to the collection directly.
Basically, what I have seen is if I follow the principle of "Tell, Don't Ask" in my client code, without worrying too much about enforcing rigid access constraints on my Domain Object properties, then I always end up with a good design.
I've got a class with well over 100 properties (it's a database mapping class) and one of the properties has to be in a method. In other words this data is not exposed via a property but via methods:
"ABCType GetABC(), SetABC(ABCType value)"
It's all very un-C#-like. I shudder when I see it.
The class needs to be serializable so it can be sent over web services, and the data exposed by the Get/Set methods needs to be serialized too. (It's in a method because of a strange thing the grid I'm using does with reflection; it can't handle objects that contain properties of the same type as the containing object. The problem property stores the original state of the database object in case a revert is required. Inefficient implementation, yes - but I'm unable to re-engineer it.)
My question is this: since only this 1 field needs custom serialization code, I'd like to use custom serialization only for calling GetABC and SetABC, reverting to basic XML serialization for the rest of the class. It'll minimize potential for bugs in my serialization code. Is there a way?
The first thing I'd try is adding a property for serialization, but hiding it from the UI:
[Browsable(false)] // hide in UI
public SomeType ABC {
get {return GetABC();}
set {SetABC(value);}
}
You can't really mix and match serialization unfortunately; once you implement IXmlSerializable, you own everything. If you were using WCF, then DataContractSerialier supports non-public properties for serialization, so you could use:
[DataMember]
private SomeType ABC {
get {return GetABC();}
set {SetABC(value);}
}
but this doesn't apply for "asmx" web-services via XmlSerializer.
Does the [Browsable] trick work at all? Assuming the custom grid uses TypeDescriptor, another option might be to hide it via ICustomTypeDescriptor, but that is a lot of work just to hide a property...