-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathReflectionEx.cs
151 lines (132 loc) · 4.79 KB
/
ReflectionEx.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
/// <summary>
/// Reflection helper class.
/// </summary>
public static class ReflectionEx
{
/// <summary>
/// Gets fields and properties into one array.
/// Order of properties / fields will be preserved in order of appearance in class / struct. (MetadataToken is used for sorting such cases)
/// </summary>
/// <param name="type">Type from which to get</param>
/// <returns>array of fields and properties</returns>
public static MemberInfo[] GetFieldsAndProperties(this Type type)
{
List<MemberInfo> fps = new List<MemberInfo>();
fps.AddRange(type.GetFields());
fps.AddRange(type.GetProperties());
fps = fps.OrderBy(x => x.MetadataToken).ToList();
return fps.ToArray();
}
/// <summary>
/// Queries value of field or property.
/// </summary>
/// <param name="member">member to query from</param>
/// <param name="target">target object</param>
/// <returns>member value</returns>
public static object GetValue(this MemberInfo member, object target)
{
if (member is PropertyInfo)
{
return (member as PropertyInfo).GetValue(target, null);
}
else
//if (member is FieldInfo)
{
return (member as FieldInfo).GetValue(target);
}
}
/// <summary>
/// Sets value to target class.
/// </summary>
/// <param name="member">member</param>
/// <param name="target">object</param>
/// <param name="value">value to set</param>
public static void SetValue(this MemberInfo member, object target, object value)
{
if (member is PropertyInfo)
{
(member as PropertyInfo).SetValue(target, value, null);
}
else if (member is FieldInfo)
{
(member as FieldInfo).SetValue(target, value);
}
}
/// <summary>
/// Deep clones specific object.
/// Analogue can be found here: https://stackoverflow.com/questions/129389/how-do-you-do-a-deep-copy-an-object-in-net-c-specifically
/// This is now improved version (list support added)
/// </summary>
/// <param name="obj">object to be cloned</param>
/// <returns>full copy of object.</returns>
public static object DeepClone(this object obj)
{
Type type = obj.GetType();
if (obj is IList)
{
IList list = ((IList)obj);
IList newlist = (IList)Activator.CreateInstance(obj.GetType(), list.Count);
foreach (object elem in list)
newlist.Add(DeepClone(elem));
return newlist;
} //if
if (type.IsValueType || type == typeof(string))
{
return obj;
}
//else if (type.IsArray)
//{
// Type elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));
// var array = obj as Array;
// Array copied = Array.CreateInstance(elementType, array.Length);
// for (int i = 0; i < array.Length; i++)
// copied.SetValue(DeepClone(array.GetValue(i)), i);
// return Convert.ChangeType(copied, obj.GetType());
//}
else if (type.IsClass)
{
object toret = Activator.CreateInstance(obj.GetType());
MemberInfo[] fields = type.GetFieldsAndProperties();
foreach (MemberInfo field in fields)
{
// Don't clone
if (
// Solution / parent reference
field.Name == "parent" ||
// projects list, no need to clone, as it's copy of solution projects
field.Name == "nodes" ||
// backreference to solution.
field.Name == "solution" )
{
continue;
}
// Constant fields, don't care.
FieldInfo fi = field as FieldInfo;
if (fi != null && fi.IsLiteral && !fi.IsInitOnly)
continue;
// Properties with only get or only set, not copyable.
PropertyInfo pi = field as PropertyInfo;
if( pi != null && (!pi.CanRead || !pi.CanWrite) )
continue;
object fieldValue = field.GetValue(obj);
if (fieldValue == null)
continue;
field.SetValue(toret, DeepClone(fieldValue));
}
return toret;
}
else
{
// Don't know that type, don't know how to clone it.
//if (Debugger.IsAttached)
// Debugger.Break();
return null;
}
} //DeepClone
}