Good practices

Your type design can help UniversalSerializer in doing its job.

An adequate parametric constructor

If your type can not have a default (no parameters) constructor, its fields will be used by UniversalSerializer when looking for the parameters of the constructors.

Example:

public class ParametricConstructedClassWithPrivateField
{
  private readonly int[] IntArray;

  public ParametricConstructedClassWithPrivateField(int[] intArray)
  {
    this.IntArray = intArray;
  }
}

In this example, UniversalSerializer detects it can use the parametric constructor since the parameter has the same type and nearly same name than a field.
It will serialize the private field and use its value on deserialization, calling the constructor.

Suggestion: give the same name to the field and to the constructor parameter, or something close.
Example: if the parameter is named "Info", you can name the field "Info", "_Info", "info" or "_info".

 

A true IList<T>, not only an Enumerable

UniversalSerializer needs to be able to add items to this enumeration in order to deserialize it.
Problem: IEnumerable, IEnumerable<T> and ICollection define a read-only collection.

Please note the generic ICollection<T> is a writable collection while ICollection (not generic) is read-only.

Suggestion: inherit from IList<T> (generic) or from IList (not generic) when possible.

If, for some reason, you do not want your type to inherit from IList nor ICollection<T>, you can write a function as Add or Insert.
Example:

public class L : IEnumerable<int>
{
  public void Add(int item)
  {
    ...
  }
  ...
}

Please note this method (Add or Insert) can be private.