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); }
}
}
Related
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; }
}
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;
}
}
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.
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("{...}");
For a class that can be saved in a persistence medium i am creating Interface called IPersistable which is designed to provide a persistenceId.
public interface IPersistable
{
private readonly string persistenceId;
}
Certainly i can't do the above since Interfaces do not allow fields. If it did i would have done below to accomplish it
Public Class Customer
{
private readonly string persistenceId;
Public string UserId
{
get{return persistenceId};
}
Public Customer(string customerId)
{
persistenceId = customerId;
}
}
I already am inheriting a class hence not possible to do multiple inheritance. I could use composition but Interface seems right thing here. Show me a neat hack to do the above instead of adding a property to each class that needs to be persisted.
Question
If possible, can a class that Interfaces with IPersistable change the name of the property( if persistenceId is a property), to something meaningful ?
An interface won't help you if you want to be able to persist existing types such as int or string. Maybe instead of an interface you could use a wrapping class? Something like:
class Persistable<T>
{
public Persistable<T>(string PersistanceId, T Data)
public readonly string PersistanceId;
public readonly T Data;
}
What's wrong with?
public interface IPersistable
{
String PersistenceId { get; }
}
Public Class Customer : IPersistable
{
public string PersistenceId { get; private set; }
public string UserId {
get { return PersistenceId; }
}
.
.
.
}
Try something like this:
public interface IPersistable<TType>
{
TType PersistenceId { get; }
}
public abstract PersistableEntity<TType> : IPersistable<TType>
{
private TType persistenceId;
public TType PersistenceId
{
get { return persistenceId; }
}
public PersistableEntity(TType persistenceId)
{
this.persistenceId = persistenceId;
}
}
public class Customer : PersistableEntity<string>
{
public Customer(string persistenceId)
: base(persistenceId)
{
}
}