C# Заполнение объектов с помощью PropertyInfo

У меня есть следующие классы:

Пользователь

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; }
}

Интерес

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; }
}

и WSReturnInterestBetById

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

Я заполняю WSReturnUserGetById данными о пользователе, используя этот фрагмент кода:

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;
}

У меня также есть одна функция для заполнения списка объектов

общедоступный список PopulateObjectList (объекты IEnumerable), где 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;
}

Когда я использую этот код, он работает, за исключением свойства «Интересы» в User и WSReturnUserGetById, потому что тип другой. Итак, я пытаюсь настроить и использовать эту функцию, чтобы она работала:

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;
    }

}

Проблема в том, что я не знаю, как получить информацию о классе свойства, поэтому я могу выполнить рекурсию. Кто-нибудь знает, как это сделать?


person DanielD    schedule 02.08.2014    source источник
comment
Что вы имеете в виду под получить информацию о классе свойства? Вы спрашиваете, как получить тип владельца свойства через отражение?   -  person    schedule 02.08.2014
comment
Вы имеете в виду, как получить тип дженерика, верно?   -  person NoOne    schedule 02.08.2014


Ответы (2)


Насколько я понимаю, вы хотите рекурсивно вызвать populateCompletedObj<T,U>. Это можно легко сделать, но я бы предложил некоторые изменения в первую очередь.

  • U не нужен, я бы удалил это из общего определения и просто использовал вместо него object.
  • Оберните populateCompletedObj в свой собственный объект (если это еще не сделано)

Получение метода для рекурсивного вызова выглядит примерно так:

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

Затем вы можете вызвать этот метод следующим образом:

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

После всего, что я закончил с этим:

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;
}

При этом вы можете просто сериализовать из одного типа и десериализовать в другой, используя что-то вроде JSON.net, и избежать всей этой боли.

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);
}

Вот суть всего кода:

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

person Gary.S    schedule 02.08.2014
comment
Ну, я не думал об использовании JSON.net, ха-ха. Это решило мою проблему. Спасибо! - person DanielD; 04.08.2014

Если я понял, что вы имеете в виду, вы ищете способ получить внутренний тип общего.

Это string в List<string>.

Вы можете добиться этого, используя этот код:

PropertyInfo objPf = typeof(T).GetProperty(p.Name);
var type = pi.PropertyType.GetGenericArguments()[0];
person NoOne    schedule 02.08.2014