You need to implement something in your object that determines the order of the properties so as to establish a convention for the order of the parameters in the array.
One option is to create a Attribute to define the order of each property.
There are several advantages to using attributes: you are not subject to field order fragility, you may have more properties in your class even if you do not want to set value for them from the array, etc.
In addition to the advantages, using attributes, you can define more metadata such as the format of the date received in the string, number of decimals, required properties, validations, etc. And you can also create a graphical interface to, from these metadata of the attributes, show a documentation always updated of how is the expected layout (order and type of fields, data format, etc.).
In this solution, I take advantage of the attributes to specialize the string conversion:
public class DadoAttribute : Attribute
{
public int Ordem { get; private set; }
public DadoAttribute(int ordem)
{
this.Ordem = ordem;
}
public virtual object ConverteValor(string valor, Type type)
{
return Convert.ChangeType(valor, type);
}
}
Note that the attribute knows the conversion logic, so I can implement specific attributes for specific types, such as date:
public class DadoData : DadoAttribute
{
private String formatoData;
public DadoData(int ordem, String formatoData) : base(ordem)
{
this.formatoData = formatoData;
}
public override object ConverteValor(string valor, Type type)
{
return DateTime.ParseExact(valor, formatoData, null);
}
}
And then you can decorate each property by informing its order and eventually an attribute with special data conversion capability, thus:
public class Objeto
{
[Dado(0)]
public int _numero { get; set; }
[DadoData(1, "dd-MM-yyyy")]
public DateTime _data { get; set; }
[Dado(2)]
public string _palavra { get; set; }
[Dado(3)]
public decimal _decimal { get; set; }
}
Note that for the date property I reported a specialized attribute.
Finally, you get the properties of your object by ordering them by the attribute you entered in each one, and you arrow their respective value using the conversion knowledge of the attribute.
You can create a class to represent the property in order to specialize its value-setting logic in the object using the conversion knowledge contained in the attribute:
public delegate object ConverteValor(string valor, Type type);
public class Propriedade
{
private ConverteValor conversor;
private PropertyInfo property;
public Propriedade(PropertyInfo property, ConverteValor conversor)
{
this.conversor = conversor;
this.property = property;
}
public void SetValue(object objeto, string valor)
{
property.SetValue(objeto, conversor(valor, property.PropertyType));
}
}
And the logic to read get the properties and set the value in each one is like this:
public static class FabricaObjeto
{
public static Objeto Constroi(string[] dadosOrdenados)
{
var typeAtributoDado = typeof(DadoAttribute);
var propriedades =
from propriedade in typeof(Objeto).GetProperties()
where Attribute.IsDefined(propriedade, typeAtributoDado)
orderby
((DadoAttribute)Attribute.GetCustomAttribute(propriedade, typeAtributoDado)).Ordem
select new Propriedade (propriedade,
((DadoAttribute)Attribute.GetCustomAttribute(propriedade, typeAtributoDado))
.ConverteValor);
var objeto = new Objeto();
var indiceDado = 0;
foreach (var propriedade in propriedades)
{
propriedade.SetValue(objeto, dadosOrdenados[indiceDado]);
indiceDado++;
}
return objeto;
}
}
An example of consumer code:
public class Program
{
public static void Main(string[] args)
{
var dadosOrdenados = new string[] { "1", "13-01-2015", "abc", "0.123" };
var objeto = FabricaObjeto.Constroi(dadosOrdenados);
Console.WriteLine(
string.Format("{0} - {1} - {2} - {3}"
, objeto._numero, objeto._data, objeto._palavra, objeto._decimal));
// saída: 1 - 13/01/2015 00:00:00 - abc - 0.123
}
}
This solution is useful, for example, to create object instances from reading delimited text file (csv). Sometimes we can’t dictate the file format and our code will never escape from knowing the sequence of the fields.
See working on .Net Fiddle.
The big problem of using array is to ensure the order of the fields. Nothing guarantees that the application has how to know which field goes where. For this case, the ideal would be a dictionary. At least defined key and value would be simpler to perform the conversion.
– Leonel Sanches da Silva
If the data in the array comes from reading a delimited text file, the application does not escape having to know the order of the values.
– Caffé