.NET反射 - 检查2个类是否作为彼此的成员添加

时间:2017-11-08 13:29:16

标签: c# reflection

如何检查2个类是否作为彼此的成员添加。

class Team
{
   Driver driver{ get; set;}
   Driver codriver{ get; set;}
}

class Driver
{
   Team parentTeam{ get; set;}
}

我使用以下方法获取属性: -

PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (PropertyInfo property in properties)
{
   ////if (!isParent) //need to find this.
   //{
   object propertyValue = property.GetValue(obj);
   if (propertyValue != null)
   {
      // Get the deep clone of the field in the original object and assign the clone to the field in the new object.
      property.SetValue(copiedObject, CloneProcedure(propertyValue));
   }
   //}
}

我想跳过第一个类,当迭代第二个时,它是第二个属性。 注意:你们中的一些人可能觉得我的课程声明不正确,但这是遗留系统,我没有机会重组课程。

我尝试过DeclaringType,我得到了property.DeclaringType但是obj.GetType()。DeclaringType为null。

3 个答案:

答案 0 :(得分:1)

从外观来看,你是深度克隆,而你实际上并不想跳过父 Type ,你只是不想要相同的实例< / em>生成多个克隆。

您可以做的是保留一个Dictionary<object, object>来保留以前克隆的实例的引用:

object CloneProcedure(object o, Dictionary<object, object> cloned)
{
    object clone;
    if (cloned.TryGetValue(o, out clone))
    {
        // this object has been cloned earlier, return reference to that clone
        return clone;
    }

    clone = Activator.CreateInstance(o.GetType());
    cloned[o] = clone;

    PropertyInfo[] properties = ...
    foreach ...
    {
        ...
        property.SetValue(copiedObject, CloneProcedure(propertyValue, cloned));
    }
}

这确保不会多次克隆任何对象,如果多个属性指向同一个实例,则克隆也将指向同一个克隆实例。

答案 1 :(得分:0)

试试这个

PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (PropertyInfo property in properties)
{
   if (property.PropertyType == typeof(Parent)) 
   {
       object propertyValue = property.GetValue(obj);
       if (propertyValue != null)
       {
          // Get the deep clone of the field in the original object and assign the clone to the field in the new object.
          property.SetValue(copiedObject, CloneProcedure(propertyValue));
       }
   }
}

如果要允许继承,可以使用Type.IsAssignableFrom

答案 2 :(得分:0)

如果这对任何人都有好处,我会发布我的最终深度复制实用程序

 public static class DeepCloneHelper
{
    private static string[] _excludedPropertyNames = null;

    /// <summary>
    /// Get the deep clone of an object.
    /// </summary>
    /// <typeparam name="T">The type of the source.</typeparam>
    /// <param name="source">It is the object used to deep clone.</param>
    /// <param name="propertyNames"></param>
    /// <returns>Return the deep clone.</returns>
    public static T DeepClone<T>(T source, string[] propertyNames = null)
    {
        if (source == null)
        {
            throw new ArgumentNullException("Object is null");
        }
        if (propertyNames != null) { _excludedPropertyNames = propertyNames; }
        return (T)CloneProcedure(source, new Dictionary<object, object>());
        // return target;
    }

    /// <summary>
    /// The method implements deep clone using reflection.
    /// </summary>
    /// <param name="source">It is the object used to deep clone.</param>
    /// <param name="cloned"></param>
    /// <returns>Return the deep clone.</returns>
    private static object CloneProcedure(Object source, Dictionary<object, object> cloned)
    {
        if (source == null)
        {
            return null;
        }

        object clone;
        if (cloned.TryGetValue(source, out clone))
        {
            // this object has been cloned earlier, return reference to that clone
            return clone;
        }

        Type type = source.GetType();

        // If the type of object is the value type, we will always get a new object when 
        // the original object is assigned to another variable. So if the type of the 
        // object is primitive or enum, we just return the object. We will process the 
        // struct type subsequently because the struct type may contain the reference 
        // fields.
        // If the string variables contain the same chars, they always refer to the same 
        // string in the heap. So if the type of the object is string, we also return the 
        // object.
        if (type.IsPrimitive || type.IsEnum || type == typeof(string))
        {
            return source;
        }
        // If the type of the object is the Array, we use the CreateInstance method to get
        // a new instance of the array. We also process recursively this method in the 
        // elements of the original array because the type of the element may be the reference 
        // type.
        else if (type.IsArray)
        {
            Type typeElement = Type.GetType(type.FullName.Replace("[]", string.Empty) + "," + type.Assembly.FullName);
            var array = source as Array;
            Array copiedArray = Array.CreateInstance(typeElement, array.Length);
            cloned[source] = copiedArray;

            for (int i = 0; i < array.Length; i++)
            {
                // Get the deep clone of the element in the original array and assign the 
                // clone to the new array.
                copiedArray.SetValue(CloneProcedure(array.GetValue(i), cloned), i);

            }
            return copiedArray;
        }

        else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
        {
            if (typeof(IList).IsAssignableFrom(type))
            {
                var collection = (IList)Activator.CreateInstance(type);
                cloned[source] = collection;

                foreach (var element in source as IEnumerable)
                {
                    collection.Add(CloneProcedure(element, cloned));
                }
                return collection;
            }
            else if (type.IsGenericType)
            {
                var objectType = type.GetGenericArguments().Single();
                if (typeof(IList<>).MakeGenericType(objectType).IsAssignableFrom(type) ||
                    typeof(ISet<>).MakeGenericType(objectType).IsAssignableFrom(type))
                {
                    var collection = Activator.CreateInstance(type);
                    cloned[source] = collection;

                    var addMethod = collection.GetType().GetMethod("Add");
                    foreach (var element in source as IEnumerable)
                    {
                        addMethod.Invoke(collection, new[] { CloneProcedure(element, cloned) });
                    }
                    return collection;
                }
            }
            return source;
        }
        // If the type of the object is class or struct, it may contain the reference fields, 
        // so we use reflection and process recursively this method in the fields of the object 
        // to get the deep clone of the object. 
        // We use Type.IsValueType method here because there is no way to indicate directly whether 
        // the Type is a struct type.
        else if (type.IsClass || type.IsValueType)
        {
            object copiedObject = Activator.CreateInstance(source.GetType());
            cloned[source] = copiedObject;

            // Get all PropertyInfo.
            PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (PropertyInfo property in properties)
            {
                if (_excludedPropertyNames == null || !_excludedPropertyNames.Contains(property.Name))
                {
                    object propertyValue = property.GetValue(source);
                    if (propertyValue != null && property.CanWrite && property.GetSetMethod() != null)
                    {
                        // Get the deep clone of the field in the original object and assign the 
                        // clone to the field in the new object.
                        property.SetValue(copiedObject, CloneProcedure(propertyValue, cloned));
                    }
                }
            }
            return copiedObject;
        }
        else
        {
            throw new ArgumentException("The object is unknown type");
        }
    }
}

参考:https://code.msdn.microsoft.com/windowsdesktop/CSDeepCloneObject-8a53311e