I have a little problem, which I'm guessing should have been solved with better code design from the beginning. But here I am.
I have an app with a pretty large user base. The app uses profiles. The profiles are are deserialized from file when starting the app.
In new releases the profile class sometimes gets new properties. If the profile is deserialized from an older version these properties will be uninitialized. Where as they will have some set default values if the profile is created with the current version of the app.
Is there a simple way of initializing a property with a default value if the serialized version doesn't have it?
You can specify a method to run after deserializing where you could set default values:
using System.Runtime.Serialization;
[Serializable]
class Car
{
public int Id { get; set; }
public string Make { get; set; }
public int Doors { get; set; }
public string Foo { get; set; } // added property
...
[OnDeserialized()]
internal void OnDeserializedMethod(StreamingContext context)
{
if (string.IsNullOrEmpty(this.Foo))
this.Foo = "Ziggy";
}
}
You might want to consider ProtoBuf-NET which is a data contract binary serializer. It is much more flexible about these things, more options, faster and creates smaller output. I just double checked to be sure, and ProtoBuf will not undo fields it doesnt have information for. So:
[ProtoContract]
class Car
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Make { get; set; }
[ProtoMember(3)]
public int Doors { get; set; }
[ProtoMember(4)]
public string Foo { get; set; } // new prop
public Car()
{
this.Foo = "Ziggy";
}
...
}
If there is no serialized value for Foo, the old value from the ctor is retained. So you could initialize new properties there and not have to worry about them getting reset to null. If you have a lot of properties like Bitmap, Font and Rectangle you might want to stay with the BinaryFormatter.
Related
I am currently creating an application for migrating data, The data can be very complex as it can contain itself e.g
--Boss
--Supervisor
---Manager
---Supervisor
---Boss
----Employee
The application then shows the data as a checkbox where a use can select what data they want, the issue now is that behind the scenes I load the data and want to keep a separate list of the original source where i get the data from.
The issue is, if i wanted to decrease the size of the Boss object(the top level one, would setting null on the supervisor object decrease its memory size, or would it just create an orphaned element in memory and just increase my application memory use?
NB. The Elements the in hierarchy all come from the same base type and are in the format of List ..of Lists...Of lists ..,etc with other properties attached to them that might be of the same base type that cannot be shown on the hierarchy.
This is an example of the code i am using
public class AttributeConversion : BaseConversion
{
public AttributeConversion(string displayName)
: base(displayName)
{
//set up value
}
public AttributeConversion()
{
//default constructor for the serializer class
}
[XmlIgnore]
[Identity]
public int AttributeID { get; set; }
public string Name { get; set; }
//[XmlIgnore]
public int DataTypeID { get; set; }
[ControlAttribute]
[XmlArray("AttributeLookupSets")]
[XmlArrayItem("AttributeLookupSet")]
public List<AttributeLookupSetConversion> AttributeLookupSetConversions { get; set; }
public AttributeLookupSourceConversion AttributeLookupSource { get; set; }
[XmlElement("AttributeSetAttribute")]
public AttributeSetAttributeConversion AttributeSetAttributeConversion { get; set; }
[XmlElement("AttributeInteger")]
public AttributeIntegerConversion AttributeIntegerConversion { get; set; }
[XmlElement("AttributeFloat")]
public AttributeFloatConversion AttributeFloatConversion { get; set; }
[XmlElement("AttributeText")]
public AttributeTextConversion AttributeTextConversion { get; set; }
[XmlElement("AttributeDate")]
public AttributeDateConversion AttributeDateConversion { get; set; }
So in this particular instance, I would like to nullify all the objects with either XmlElement or XmlArray attributes. The goal is to flatten that hierarchy and then set all items to null, that way I can use the list for reference as to what Items I have at anytime in the hierarchy of objects, But I am unsure of the memory usage, so I wanted to at least ensure i shed any memory i might be wasting.
I have a bunch of settings that can be one of many types. For example, URL, text, number, etc. Based on other posts I came up with the following that seems to work okay:
public abstract class SettingViewModel
{
public string Name { get; set; }
public string Description { get; set; }
public SettingType Type { get; set; }
public string DefaultValue { get; set; }
public Module? Module { get; set; }
}
public class SettingViewModel<T> : SettingViewModel
{
[Required]
public T Value { get; set; }
}
My biggest problem with this is that when it comes time to read the values in Value for each setting I want to do have a method like. I wouldn't want to change the shape of this method really, because I want to keep it generic and it will be exposed as a Controller Method in MVC
public void Update(SettingViewModel Setting)
{
GS_SysConfig setting = new GS_SysConfig();
//might also just use a util function to convert to string based on the type of Value
setting.ConfigVal = Setting.Value.ToString(; //Value is not a field in the abstract class
db.SaveChanges();
}
This won't work because Value is not a field in the parent class, and I suppose I could come up with some way of doing casting and and getting types and such, but it seems messy and not very elegant. Is there a better approach to tryign to accomplish what I'm trying to do?
Update:
ConfigVal is of type String
I have the following class structure in my application:
[ProtoContract]
public abstract class WebSyncedObject
{
[ProtoMember(1)]
public DateTime SystemTime { get; set; }
[ProtoMember(2)]
public bool TimeSynchronized { get; set; }
[ProtoMember(3)]
public ulong RelativeTime { get; set; }
[ProtoMember(4)]
public Guid BootID { get; set; }
protected WebSyncedObject()
{
BootID = BootID.GetBootID();
if (BootID == Guid.Empty) return;
TimeSynchronized = Time.TimeSynchronized;
RelativeTime = Time.RelativeTime;
SystemTime = DateTime.Now;
}
}
[ProtoContract]
public class GPSReading : WebSyncedObject
{
[ProtoMember(1)]
public DateTime SatelliteTime { get; set; }
[ProtoMember(2)]
public decimal Latitude { get; set; }
[ProtoMember(3)]
public decimal Longitude { get; set; }
[ProtoMember(4)]
public int NumSatellites { get; set; }
[ProtoMember(5)]
public decimal SpeedKM { get; set; }
}
[ProtoContract]
public class TemperatureReading : WebSyncedObject
{
[ProtoMember(1)]
public decimal Temperature { get; set; }
[ProtoMember(2)]
public int NodeID { get; set; }
[ProtoMember(3)]
public string ProbeIdentifier { get; set; }
}
I then construct a List<WebSynchedObject> with data of both types, and try to serialize with Protobuf-net when I get the following exception:
InvalidOperationException
Unexpected sub-type: Logger.TemperatureReading
I've read about the ProtoInclude attribute, but I don't want to use that as my code needs to be easily extendable, and I'm not sure on how the numbering on the RuntimeTypeModel approach is supposed to work, since I've also seen warnings about generating that automagically.
Is there any way to achieve this whilst making it extendable?
Ultimately, there needs to be a robust, reliable and repeatable way of the library identifying a specific sub-type (GPSReading, etc) with a unique identifier (a field-number). In many cases, the most convenient way to do that is via attributes. However, if this is not an option, you can also do this at runtime - perhaps reading the identifiers some configuration file. It would not be a good idea to just say (at runtime) "find all the available sub-types, order them alphabetically, and increment them starting at (say) 10", because in a later build you might have added an AltitudeReading, which would change the number of everything, breaking the existing data. But as long as you can define these in a repeatable manner, then all is good. For example, with attributes...
[ProtoInclude(10, typeof(GPSReading))]
[ProtoInclude(11, typeof(TemperatureReading))]
[ProtoInclude(12, typeof(AltitudeReading))]
But you could also do something in a text file, or an xml configuration file... maybe:
<add key="10" type="Some.Namespace.GPSReading"/>
<add key="11" type="Some.Namespace.TemperatureReading"/>
<add key="12" type="Some.Namespace.AltitudeReading"/>
and add you own code that reads the config file, and calls:
int key = int.Parse(element.GetAttributeValue("key"));
Type type = someAssembly.GetType(element.GetAttributeValue("type"));
RuntimeTypeModel.Default[typeof(WebSyncedObject)].AddSubType(key, type);
Again, to emphasize: the important thing is that the numbers associated with each sub-type must be robustly repeatable in the future. As long as you can guarantee that, it is not required to use attributes. But the model does need to know the identifiers.
I have a 3rd party application that provides an object with many "attributes", which are simply pairs of (string) keys and values. The value types can be either strings, DateTime, Int32 or Int64.
I need to create my own class to represent this object, in a convenient way. I'm creating a WCF service that provides this object to clients, so I need it to be very easy and clean.
The keys of the attributes will be presented as an Enum for the clients (to hide the information of the specific key strings of the 3rd party application). However, I'm not sure how to represent the values. Here are some of the options:
Option 1: Have different collection per attribute values, seems ugly but will be very easy for clients to use
public class MyObject
{
public Dictionary<MyTextAttributeKeysEnum, string> TextAttributes { get; set; }
public Dictionary<MyDateAttributeKeysEnum, DateTime> DateAttributes { get; set; }
public Dictionary<MyNumAttributeKeysEnum, long> NumericAttributes { get; set; }
public string Name { get; set; }
public string Id{ get; set; }
Option 2: Convert all of the attributes to strings
public class MyObject
{
public Dictionary<MyAttributeKeysEnum, string> MyAttributes { get; set; }
public string Name { get; set; }
public string Id{ get; set; }
Option 3: Keep them as objects, let the clients bother with casting and converting
public class MyObject
{
public Dictionary<MyAttributeKeysEnum, object> MyAttributes { get; set; }
public string Name { get; set; }
public string Id{ get; set; }
Using several dictionaries just doesn't look nice :) But might work in some scenarios.
If you are absolutely sure that string is enough for all - go with strings. But if some other code would need to parse it - that's going to be expensive.
If you want a really simple straightforward solution - just go with objects. Even though it would introduce boxing/unboxing for value types (forget it if you don't operate thousands of objects) and you'd lose type information on values this solution might still work just fine.
Also you might consider introducing an intermediate class for a value. Something like
public Dictionary<MyAttributeKeysEnum, PropertyBagValue> MyAttributes { get; set; }
public class PropertyBagValue
{
public object AsObject { get; set; }
public string AsString { get; set; }
public int AsInt { get; set; }
// ...
}
Internally you could store your value in a variable of the original type (int in an int variable, string in a string variable, etc., i.e. have a separate variable for each type) and then you can avoid type conversion. Also you could wrap your dictionary in another class, add some usefull accessors and make it look nicer. I don't know how does this fit into your infrastructure though.
How about making you DataContract class abstract and provide dictionaries with types you need in derived classes:
[DataContract]
[KnownType(typeof(My3dPartyObjectString))]
[KnownType(typeof(My3dPartyObjectInt64))]
public abstract class My3dPartyObjectBase
{
// some common properties
}
[DataContract]
public class My3dPartyObjectString : My3dPartyObjectBase
{
public Dictionary<3PAttributeKeysEnum, string> MyStringAttributes { get; set; }
}
[DataContract]
public class My3dPartyObjectInt64 : My3dPartyObjectBase
{
public Dictionary<3PAttributeKeysEnum, long> MyStringAttributes { get; set; }
}
Then client will have to analyse real type of returned object and get collection of attributes based on type. That would be close to your 3d option, but client will at least have some type safety at response-object level.
I'm trying to whip up a POC of a system which allows you to create and modify enumerations that are eventually used in an application using the front-end. Something like dynamic enums.
For example, in a hypothetical bug tracker application, we can have a status enum that could have values of open,accepted and closed. All these enums (and their corresponding values) can be changed in real-time via the UI, so it is possible for an admin to come up with a new reassigned value for example (through an Admin page, most probably) somewhere down the application's lifetime. It would also be possible to create new enums as well, which in turn have their own values (for example, a complexity enum).
The way I'm currently envisioning it is that I'll have an Enumeration class, which has a 1:* referential with an EnumerationValue class.
public class Enumeration {
public string Name { get; set; }
public ICollection<EnumerationValue> Values { get; set; }
}
public class EnumerationValue {
public string Name { get; set; }
public string Description { get; set; }
}
That's the easy part. When I get to creating the entity that actually uses these dynamic enums, I hit a snag.
Let's say I'm creating the BugRecord entity, which consequently has a Status property. Following the logic above, I'd have to write it along the lines of:
public class BugRecord {
public EnumerationValue Status { get; set; }
}
But given that I could have lots of different Enumerations (and EnumerationValues), is there a way for me to restrict BugRecord.Status values to only EnumerationValues in the status Enumeration? If not how would you recommend I tackle a problem of this kind?
Create a third Entity/JoinTable EnumerationChoice and use it to map the BugRecord to the EnumerationValue
public class EnumerationChoice {
public Enumeration EnumerationCategory { get; set; }
public EnumerationValue Value { get; set; }
}
BugRecord now becomes:
public class BugRecord {
public EnumerationChoice BugType { get; set; }
public EnumerationChoice Status { get; set; }
}
The data would now look like:
BugRecord:
EnumerationChoice:
-BugType
-BugTypeValue1
EnumerationChoice:
-Status
-Open
This way, when you try to populate the EnumerationChoice, you can reference the EnumerationCategory to get the valid EnumerationValues assigned to it.