samedi 30 septembre 2017

Efficient nested if or other alternatives when looking for two attributes on a property?

I'm creating some attributes to use on properties, that are part of types manipulated by an extension method I created.

the method ChargeFrom assign the value of an object to another, mapping the same properties names and types, so if I have two classes like:

class Book
{
 public int Id {get; set;}
 public string Title {get; set;}
 public decimal Price {get; set;}
}

class BookViewModel
{
 public int Id {get; set;}
 public string Title {get; set;}
 public decimal Price {get; set;}
}

when I have an object of type Book:

var book = new Book{Id=1, Title = "T1", Price = 345};

I can instansiate a BookViewModel Like this :

var bookModel = new BookViewModel();
bookModel.ChargeFrom(book);

I use reflection in this method. but the method itself is not why I ask the question. in the library I have two attributes : SourcePropertyAttribute which is used to specify explicitly a different property name on the source object. and DeepChargingAttribute which loop through a property if it's a custom type (if the user decided so!) and set its value from the corresponding property on the source object (ex: AuthorViewModel in BookViewModel, corresponds to Author property in Book class). I'm new in Attributes programming, though it shows no different, except on taking such decision. my problem is that sometimes a property may have both attributes: DeepChargingAttribute and SourcePropertyAttribute, or only one of them.

I don't know if the nested if is the key solution for that case, and if so, what is the most efficient way doing it?

here's my code:

static void ChargeProperties(object target, object source)
        {

            PropertyInfo[] targetProperties = target.GetType().GetProperties();
            PropertyInfo[] sourceProperties = source.GetType().GetProperties();

            foreach (PropertyInfo propTarget in targetProperties)
            {

                foreach (PropertyInfo propSource in sourceProperties)
                {
                    if (propTarget.Name == propSource.Name && propTarget.PropertyType == propSource.PropertyType)
                    {
                        propTarget.SetValue(target, propSource.GetValue(source));
                    }
                }
                if (Attribute.IsDefined(propTarget, typeof(SourcePropertyAttribute)))
                {
                    //there's three cases: 
                    //1 - the property has only SourcePropertyAttribute 
                    //2 - the property has only DeepChargingAttribute 
                    //3 - the property has both attributes
                    //so what is efficient way to know it while iterating overy every property?!
                    var sourcePropAttr = (SourcePropertyAttribute)Attribute.GetCustomAttribute(propTarget, typeof(SourcePropertyAttribute));
                    var sp = sourceProperties.SingleOrDefault(x => x.Name == sourcePropAttr.PropertyName);
                    if (sp == null)
                    {
                        if (sourcePropAttr.AlwaysOnSource)
                            throw new NullReferenceException($"The property name '{sourcePropAttr.PropertyName}' couldn't be found on the source object.") { Source = "Mshwf.Charger" };
                        else
                            continue;
                    }

                    propTarget.SetValue(target, sp.GetValue(source));
                }
            }
        }





Aucun commentaire:

Enregistrer un commentaire