2

C # Filling Objects with PropertyInfo

 2 years ago
source link: https://www.codesd.com/item/c-filling-objects-with-propertyinfo.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C # Filling Objects with PropertyInfo

advertisements

I have the following classes:

public partial class User
{
    public long iduser { get; set; }
    public string email { get; set; }
    public string name { get; set; }
    public System.DateTime birthdate { get; set; }
    public string about { get; set; }
    public bool active { get; set; }
    public System.DateTime created_date { get; set; }
    public System.DateTime last_update { get; set; }
    public string password { get; set; }
    public string image { get; set; }
    public string username { get; set; }
    public virtual ICollection<Interest> Interests { get; set; }
}

Interest

public partial class Interest
{

    public long idinterest { get; set; }
    public string name { get; set; }
    public bool active { get; set; }
    public System.DateTime last_update { get; set; }
    public System.DateTime created_date { get; set; }
    public string css_class { get; set; }

    public virtual ICollection<User> Users { get; set; }
}

WSReturnUserGetById

public class WSReturnUserGetById
{
    public long iduser { get; set; }
    public string email { get; set; }
    public string name { get; set; }
    public System.DateTime birthdate { get; set; }
    public string about { get; set; }
    public List<WSReturnInterestGetById> Interests { get; set; }
}

and WSReturnInterestBetById

public class WSReturnInterestGetById
{
    public long idinterest { get; set; }
    public string name { get; set; }
    public string css_class { get; set; }
}

I'm populating WSReturnUserGetById with the data on User, using this piece of code:

public T PopulateObjects<T>(object obj) where T : class, new()
{
    if (obj == null) return null;
    T Obj = new T();
    PropertyInfo[] properties = obj.GetType().GetProperties();
    foreach (PropertyInfo p in properties)
    {
        PropertyInfo objPf = typeof(T).GetProperty(p.Name);
        if (objPf != null)
        {
            if (p.PropertyType == objPf.PropertyType)
            {
                objPf.SetValue(Obj, p.GetValue(obj));
            }
        }
    }
    return Obj;
}

I also have one function to make populate a list of objects

public List PopulateObjectList(IEnumerable objects) where T: class, new() {

    List<T> response = new List<T>();
    foreach (U obj in objects)
    {
        T Obj = new T();
        if (obj != null)
        {
            PropertyInfo[] properties = obj.GetType().GetProperties();
            foreach (PropertyInfo p in properties)
            {
                PropertyInfo objPf = typeof(T).GetProperty(p.Name);
                if (objPf != null)
                {
                    if (p.PropertyType == objPf.PropertyType)
                    {
                        objPf.SetValue(Obj, p.GetValue(obj));
                    }
                }
            }
        }
        response.Add(Obj);
    }

    return response;
}

When I use that code, it works except for the property "Interests" in User and WSReturnUserGetById, 'couse the type is different. So, i'm trying to adjust, and use this function to make it work:

public object populateCompleteObj<T, U>(U mainobj) where T : class, new()
{
    if (mainobj.GetType().IsGenericType && mainobj is IEnumerable)
    {
        List<T> response = new List<T>();
        foreach (object obj in (IEnumerable)mainobj)
        {
            T Obj = new T();
            if (obj != null)
            {
                PropertyInfo[] properties = obj.GetType().GetProperties();
                foreach (PropertyInfo p in properties)
                {
                    PropertyInfo objPf = typeof(T).GetProperty(p.Name);
                    if (objPf != null)
                    {
                        if (typeof(IEnumerable).IsAssignableFrom(objPf.PropertyType))
                        {
                            objPf.SetValue(Obj, populateCompleteObj<'objpf property class', 'obj property class'>(p.GetValue(obj)));
                        }
                        else if (p.PropertyType == objPf.PropertyType)
                        {
                            objPf.SetValue(Obj, p.GetValue(obj));
                        }
                    }
                }
            }
        }

    }
    else
    {
        if (mainobj == null) return null;
        T Obj = new T();
        PropertyInfo[] properties = mainobj.GetType().GetProperties();
        foreach (PropertyInfo p in properties)
        {
            PropertyInfo objPf = typeof(T).GetProperty(p.Name);
            if (objPf != null)
            {
                if (p.PropertyType == objPf.PropertyType)
                {
                    objPf.SetValue(Obj, p.GetValue(mainobj));
                }
            }
        }
        return Obj;
    }

}

The problem is that I don't know how to get the class of the property info, so a can do the recursion. Does anyone knows how to do this?


From what i understand you want to recursively call populateCompletedObj<T,U>. This can easily be done but I would suggest some changes first.

  • U is not needed, i would remove this from the generic definition and just use object instead.
  • Wrap the populateCompletedObj in its own object (if it isn't already)

Getting the method to call recursively then looks something like this:

// this.GetType is the class that contains the method to call
var recurseMethod = this.GetType().GetMethod("populateCompletedObj").MakeGenericMethod(objPf.PropertyType);

You can then call this method like so:

// Invoke the method on the current instance with the property
recurseMethod.Invoke(this, new object[1] {p.GetValue(obj) });

After all that i ended up with this:

public TDest ReflectionCopy<TDest>(object srcVal)
    where TDest : class, new()
{
    if (srcVal == null) { return null; }
    TDest dest = new TDest();
    var props = srcVal.GetType().GetProperties();
    foreach (PropertyInfo p in props)
    {
        PropertyInfo objPf = typeof(TDest).GetProperty(p.Name);
        if (objPf != null)
        {
            if (objPf.PropertyType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(objPf.PropertyType))
            {
                var destCollType = objPf.PropertyType.GenericTypeArguments[0];
                var recurse = this.GetType().GetMethod("ReflectionCopy").MakeGenericMethod(destCollType);
                IEnumerable srcList = (IEnumerable)p.GetValue(srcVal);
                IList destlst = (IList)Activator.CreateInstance(objPf.PropertyType);
                foreach(var srcListVal in srcList)
                {
                    var destLstVal = recurse.Invoke(this, new object[1] { srcListVal });
                    destlst.Add(destLstVal);
                }
                objPf.SetValue(dest, destlst);
                continue;
            }

            if (p.PropertyType == objPf.PropertyType)
            {
                objPf.SetValue(dest, p.GetValue(srcVal));
            }
        }
    }
    return dest;
}

That all being said, you could just serialize from one type and deserialize to another using something like JSON.net and avoid all of this pain.

public TDest SerializeCopy<TDest>(object srcVal)
    where TDest : class, new()
{
    if (srcVal == null) { return null; }
    var temp = JsonConvert.SerializeObject(srcVal);
    return JsonConvert.DeserializeObject<TDest>(temp);
}

Here is a gist with all of the code:

https://gist.github.com/garystanford/36932d38a785272ee907


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK