Creating objects that initialize themselves based on a configuration string - c#

I am coding a bunch of the following type of classes and it just seems a bit smelly to me. Basically I want to deserialze based on some json configuration of properties as well as serialize it for storage. I thought the following method would work well since I don't want to stipulate that the serialization/deserialization has to be json etc.
The code looks like this for a simple object:
public class IntegerDatasourceInstanceOptions
{
public int Start { get; set; }
public int Count { get; set; }
public IntegerDatasourceInstanceOptions()
{
}
public IntegerDatasourceInstanceOptions(string config)
{
var options = JsonConvert.DeserializeObject<IntegerDatasourceInstanceOptions>(config);
if (options != null)
{
Start = options.Start;
Count = options.Count;
}
}
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
Is this the correct way to go about this or should I use ISerializable instead?
I want to eliminate having to update all of the properties in the constructor. It's fine for a couple of properties in this case but if I have one with 30 properties it becomes a bit of a nightmare
I guess I'm just looking for some feedback as to whether this is the best way to go or not.

I tend to use a static method in instances like this, for example:
public class IntegerDatasourceInstanceOptions
{
public int Start { get; set; }
public int Count { get; set; }
public IntegerDatasourceInstanceOptions()
{
}
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
public static IntegerDatasourceInstanceOptions Create(string config)
{
return JsonConvert.DeserializeObject<IntegerDatasourceInstanceOptions>(config);
}
}
You can then just do:
var options = IntegerDatasourceInstanceOptions.Create("{...}");

Related

Validation strategy

I'm trying to build a series of attribute classes to make it easier for our development team to validate objects. The objects are POCO classes like this.
public class User
{
public string Name { get; set; }
public string Company { get; set; }
}
I want to decorate this model with a custom attribute.
public class User
{
[MustHaveValue]
public string Name { get; set; }
public string Company { get; set; }
}
Then I would create my own class implementing ValidationAttribute, the base class in .NET Framework, which belongs to System.ComponentModel.DataAnnotations.
public class MustHaveValueAttribute : ValidationAttribute
{
.
.
public override IsValid(object value)
{
// validation logic.
}
}
And then I can validate the User model whenever I want by making the set of instances like ValidationContext, List<ValidationResult>.
But in an enterprise environment, problems just can't be solved by a specific class. My validation scenario requires more complex and more flexible ways. Imagine that one of the required validation scenarios would something like this.
public class User
{
public string Name { get; set; }
public string Company { get; set; }
// Check if an item exists in this list.
[MustHaveMoreThanOneItem]
public IList<Client> Clients { get; set; }
}
Then I would need to make another attribute class
public class MustHaveMoreThanOneItemAttribute : ValidationAttribute
{
.
.
public override IsValid(object value)
{
// Let's assume this value is List<Client> for now.
// I know the exact type, so I'm going to cast it to List<Client> without further considerations
List<Client> clients = value as List<Client>;
if(clients.Count > 0) {
return true;
} else {
return false;
}
}
}
But the problem is that there are a lot of other models that have a nested list items. Try to imagine the time when I want to reuse the MustHaveMoreThanOneItem in one of the other models like...
public class Department
{
public string Name { get; set; }
[MustHaveMoreThanOneItem]
public IList<Employee> { get; set; }
}
You already know that it's not going to work because it was strongly typed only for List<Client>. So I decided to use Generic there to solve this problem.
But to my disappointment, the _Attribute interface doesn't support Generic. There's no additional implementation like _Attribute<T> : Attribute and therefore, no ValidationAttribute<T> alas!! I just cannot use Generic here !!
public class Department
{
public string Name { get; set; }
// No way to use this syntax.
[MustHaveMoreThanOneItem<Employee>]
public IList<Employee> { get; set; }
}
So I made a conclusion that Attribute must have been designed for a fixed set of validations like email format, card format, null check, and etc IMAO.
But I still want to use an attribute and give a lot of flexibilities in it to prevent the duplicated, verbose validation codes like this.
if(model.Clients.Count > 0) ...
if(model.Name != null) ...
if(model.Clients.GroupBy(x => x.Country == Country.USA).Count >= 1) ...
if(model.Clients.Where(x => x.CompanyName == Company.Google).ToList().Count > 1 ) ...
.
.
.
I want to pose two questions here.
If Attirbute supports Generic, this problem will be solved?
Is there any way to implement Generic Attribute? in order to use
[MustHaveMoreThanOneItem<Employee>] annotation on a class member?
You can generically check any object that implements IEnumerable like this:
public class MustHaveMoreThanOneItemAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// omitted null checking
var enumerable = value as IEnumerable;
var enumerator = enumerable.GetEnumerator();
if (!enumerator.MoveNext())
{
return false;
}
if (!enumerator.MoveNext())
{
return false;
}
return true;
}
}
C# by definition does not support generic type attributes, although this has been requested actively for a long time:
https://github.com/dotnet/roslyn/issues/953
https://github.com/dotnet/csharplang/issues/124
However, you can still inject a type into a validation attribute via constructor. You then can use reflection or whatever you need to define your custom validation criteria.
public class MustHaveMoreThanOneItemAttribute : ValidationAttribute
{
public Type EnumerableType { get; }
public MustHaveMoreThanOneItemAttribute(Type t)
=> this.EnumerableType = typeof(ICollection<>).MakeGenericType(t);
public override bool IsValid(object value)
{
var count = this.EnumerableType.GetProperty("Count").GetValue(value) as int?;
return (count ?? 0) > 1;
}
}
Now this allows you to use something similar to your goal:
public class Department
{
public string Name { get; set; }
[MustHaveMoreThanOneItem(typeof(Employee))]
public IList<Employee> { get; set; }
}

Serialize ValueObject as XML

You would think this is a very simple question. But after lots of searching and testing I have not found a pretty solution.
As per domain driven design I created strongly typed identifier classes. Because that helps with validation and not accidentally mixing up identifiers.
So I made a simple base class like so:
public abstract class UIDBase<T>
{
private readonly T _id;
protected UIDBase(T id)
{
_id = id;
}
public T ID
{
get { return _id; }
}
// Plus hash/equals implementation
}
And simple implementations like so:
public class SensorUID : UIDBase<string>
{
public SensorUID(string id) : base(id)
{
}
}
And then I use it:
public class SomeObject
{
public SensorUID SensorUID { get; set; }
public FileName FileName { get; set; }
}
But now when I serialize it as XML, I need a default constructor (annoying). But worse, the properties are no longer serialized as attributes.
Preferable I only want to add custom Xml serialisation code to my UIDBase class. Adding attributes or implementing an interface to tell the xml serializer that these classes should be serialized as attributes. Just like string/int/long etc.
If those value types can do it, why not my own value type?
The Xml should look like:
<SomeObject SensorUID="X" FileName="Y"/>
This seems to work, but it feels ugly:
public class SomeObject
{
[XmlIgnore]
public SensorUID SensorUID { get; set; }
[XmlIgnore]
public FileName FileName { get; set; }
[XmlAttribute("SensorUID")]
public string SensorUIDAsString
{
get { return SensorUID == null ? null : SensorUID.ID; }
set { SensorUID = new SensorUID(value); }
}
[XmlAttribute("FileName")]
public string FileNameAsString
{
get { return FileName == null ? null : FileName.ID; }
set { FileName = new FileName(value); }
}
}

How to exclude properties from serialization based on their values?

To communicate with a web API, I have created a few classes which will be serialized to XML and sent to the API. The API only accepts these XMLs if they only hold properties with non-default values.
How can I leave out properties during serialization?
Suppose I have a class as follows (simplified example):
[XmlRoot("SomeData")]
public class SomeData
{
[XmlElement("rangeX")]
public int RangeX { get; set; }
[XmlElement("rangeY")]
public int RangeY { get; set; }
[XmlElement("rangeZ")]
public int RangeZ { get; set; }
}
An object which has a non-default value for RangeX and RangeY should thus be serialized to an XML which only holds tags for rangeX and rangeY.
I have found how to leave out null values, but this is not what I want - the default value could very well be different from null.
Thanks!
You can use the "secret" ShouldSerializeXxx() method:
public bool ShouldSerializeRangeX()
{
return RangeX != someDefaultValue;
}
There are a ton of examples when you search for ShouldSerialize Default Value, it's just hard to find if you don't know what you're looking for.
Here is a link to help get you started : Defining Default Values with the ShouldSerialize and Reset Methods
You can gain full control on how the objects of your class are serialized when you implement the IXmlSerializable interface (only including the code to write the data, since that is your immediate question):
public class SomeData : IXmlSerializable
{
public int RangeX { get; set; }
public int RangeY { get; set; }
public int RangeY { get; set; }
public void WriteXml (XmlWriter writer)
{
writer.WriteStartElement("SomeData");
if (RangeX != 0)
{
writer.WriteElementString("rangeX", RangeX.ToTring());
}
if (RangeY != 0)
{
writer.WriteElementString("rangeY", RangeY.ToTring());
}
if (RangeZ != 0)
{
writer.WriteElementString("rangeZ", RangeZ.ToTring());
}
writer.WriteEndElement();
}
public void ReadXml (XmlReader reader)
{
//Implement if needed
throw new NotImplementedException();
}
public XmlSchema GetSchema()
{
return null;
}
}

Structure for Classes containing Lists of Instantiated classes to be stored in Dictionary

For my example classes to be stored are lets say:
class Race
{
public string Name { get; set; }
public DateTime Date { get; set; }
public List<Competitor> Competitors = new List<Competitor>();
}
class Competitor
{
public string Name { get; set; }
public List<Stats> SomeData = new List<Stats>():
}
class Stats
{
//Other Properties Etc
}
They are to be stored in :
class Events : Dictionary<string, List<Race>>
{
public Events()
: base()
{
}
}
And I fill the Dictionary with another class :
class GenerateEventsData
{
public Events newEvents = new Events();
public GenerateEventsData()
{
fillEvents();
}
private void fillEvents()
{
//Method to fill events.
}
}
I feel as though I'm getting to a stage where lists of classes are being stacked up and my structure is not correct.
I plan to eventually serialize the data to disk and re-use at a later date but that's beyond the bounds of this question. However if the classes aren't well structured i think i may have issues.
Thanks in advance.
you could use a generic container:
public class ListDictionary<T> : Dictionary<string,List<T>>
{
public ListDictionary():base(){}
public void AddItem(string key, T value)
{
if(ContainsKey(key))
this[key].Add(value);
else
Add(key,new List<T>{value});
}
//similar for remove and get
}
Also have a look at the repository pattern.

Facade a class without writing lots of boilerplate code?

Let's say I have a class from a 3rd-party, which is a data-model. It has perhaps 100 properties (some with public setters and getters, others with public getters but private setters). Let's call this class ContosoEmployeeModel
I want to facade this class with an interface (INavigationItem, which has Name and DBID properties) to allow it to be used in my application (it's a PowerShell provider, but that's not important right now). However, it also needs to be usable as a ContosoEmployeeModel.
My initial implementation looked like this:
public class ContosoEmployeeModel
{
// Note this class is not under my control. I'm supplied
// an instance of it that I have to work with.
public DateTime EmployeeDateOfBirth { get; set; }
// and 99 other properties.
}
public class FacadedEmployeeModel : ContosoEmployeeModel, INavigationItem
{
private ContosoEmployeeModel model;
public FacadedEmployeeModel(ContosoEmployeeModel model)
{
this.model = model;
}
// INavigationItem properties
string INavigationItem.Name { get; set;}
int INavigationItem.DBID { get; set;}
// ContosoEmployeeModel properties
public DateTime EmployeeDateOfBirth
{
get { return this.model.EmployeeDateOfBirth; }
set { this.model.EmployeeDateOfBirth = value; }
}
// And now write 99 more properties that look like this :-(
}
However, it's clear that this will involve writing a huge amount of boilerplate code to expose all the properties , and I'd rather avoid this if I can. I can T4 code-generate this code in a partial class, and will do if there aren't any better ideas, but I though I'd ask here to see if anyone had any better ideas using some super wizzy bit of C# magic
Please note - the API I use to obtain the ContosoEmployeeModel can only return a ContosoEmployeeModel - I can't extend it to return a FacededEmployeeModel, so wrapping the model is the only solution I can think of - I'm happy to be corrected though :)
The other approach may be suitable for you is to use AutoMapper to map base class to your facade here is sample code:
class Program
{
static void Main(string[] args)
{
var model = new Model { Count = 123, Date = DateTime.Now, Name = "Some name" };
Mapper.CreateMap<Model, FacadeForModel>();
var mappedObject = AutoMapper.Mapper.Map<FacadeForModel>(model);
Console.WriteLine(mappedObject);
Console.ReadLine();
}
class Model
{
public string Name { get; set; }
public DateTime Date { get; set; }
public int Count { get; set; }
}
interface INavigationItem
{
int Id { get; set; }
string OtherProp { get; set; }
}
class FacadeForModel : Model, INavigationItem
{
public int Id { get; set; }
public string OtherProp { get; set; }
}
}
Resharper allows the creation of "delegating members", which copies the interface of a contained object onto the containing object and tunnels the method calls/property access through to the contained object.
http://www.jetbrains.com/resharper/webhelp/Code_Generation__Delegating_Members.html
Once you've done that, you can then extract an interface on your proxy class.

Categories

Resources