I need to make a function that get all the properies of an object (including an children objects) This is for my error logging feature.
Right now my code always returns 0 properties.
Please let me know what I'm doing wrong, thanks!
public static string GetAllProperiesOfObject(object thisObject)
{
string result = string.Empty;
try
{
// get all public static properties of MyClass type
PropertyInfo[] propertyInfos;
propertyInfos = thisObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Static);//By default, it will return only public properties.
// sort properties by name
Array.Sort(propertyInfos,
(propertyInfo1, propertyInfo2) => propertyInfo1.Name.CompareTo(propertyInfo2.Name));
// write property names
StringBuilder sb = new StringBuilder();
sb.Append("<hr />");
foreach (PropertyInfo propertyInfo in propertyInfos)
{
sb.AppendFormat("Name: {0} | Value: {1} <br>", propertyInfo.Name, "Get Value");
}
sb.Append("<hr />");
result = sb.ToString();
}
catch (Exception exception)
{
// to do log it
}
return result;
}
here's what the object looks like:
If you want all of the properties, try:
propertyInfos = thisObject.GetType().GetProperties(
BindingFlags.Public | BindingFlags.NonPublic // Get public and non-public
| BindingFlags.Static | BindingFlags.Instance // Get instance + static
| BindingFlags.FlattenHierarchy); // Search up the hierarchy
For details, see BindingFlags.
The problem with your code is the PayPal Response types are members, NOT properties. Try:
MemberInfo[] memberInfos =
thisObject.GetMembers(BindingFlags.Public|BindingFlags.Static|BindingFlags.Instance);
Your propertyInfos array is returning 0 length for one of my classes. Changing the line to be
propertyInfos = thisObject.GetType().GetProperties();
Results in it being populated. Therefore, this line of code is your problem. It appears if you add the flag
BindingFlags.Instance
to your parameters it will return the same properties as the parameterless call. Does adding this parameter to your list fix the problem?
EDIT: Just saw your edit. Based on the code you posted, it didn't work for me either. Adding the BindingFlags.Instance made it return properties for me. I'd suggest posting the exact code you are having trouble with as your screenshot shows different code.
Related
How can i get around casting to FieldInfo? With the code below it throws InvalidCastException when derived class has i.e. bool variable.
The problem is that it also returns null as a value of field. (everything happens in last 5 lines, but i paste more for context)
{
string paramsData = ".";
if (param == null)
{
return paramsData;
}
BindingFlags bindingFlags = BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Static;
FieldInfo[] paramFields = param.GetType().GetFields(bindingFlags);
foreach (FieldInfo field in paramFields)
{
paramsData += field.Name;
Param child = (Param)field.GetValue(param);
paramsData += GetParamDataInChildren(child);
}
return paramsData;
}
It is difficult to know what you are trying to achieve, but it looks like you should be checking the type of your field before calling GetValue. For example:
if (field.FieldType == typeof(Param))
{
Param child = (Param)field.GetValue(param);
paramsData += GetParamDataInChildren(child);
}
Note that child could still be null in this case, and you should check for that if the subsequent function doesn't handle it.
[EDIT]
If you are trying to recursively get all the fields, regardless of type, you should make your recursive function take Object rather than Param and then you won't need to cast to Param as GetValue returns Object.
I'm trying to populate a generic List< T > from another List< U > where the field names match, something like the untested pseudocode below. Where I'm having problems is when T is a string, for instance, which has no parameterless constructor. I've tried adding a string directly to the result object, but this gives me the obvious error -- that a string is not of Type T. Any ideas of how to solve this issue? Thanks for any pointers.
public static List<T> GetObjectList<T, U>(List<U> givenObjects)
{
var result = new List<T>();
//Get the two object types so we can compare them.
Type returnType = typeof(T);
PropertyInfo[] classFieldsOfReturnType = returnType.GetProperties(
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Public);
Type givenType = typeof(U);
PropertyInfo[] classFieldsOfGivenType = givenType.GetProperties(
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Public);
//Go through each object to extract values
foreach (var givenObject in givenObjects)
{
foreach (var field in classFieldsOfReturnType)
{
//Find where names match
var givenTypeField = classFieldsOfGivenType.Where(w => w.Name == field.Name).FirstOrDefault();
if (givenTypeField != null)
{
//Set the value of the given object to the return object
var instance = Activator.CreateInstance<T>();
var value = field.GetValue(givenObject);
PropertyInfo pi = returnType.GetProperty(field.Name);
pi.SetValue(instance, value);
result.Add(instance);
}
}
}
return result;
}
If T is string and you have already created custom code to convert your givenObject to a string, you just need to do an intermediate cast to object to add it to a List<T>:
public static List<T> GetObjectList2<T, U>(List<U> givenObjects) where T : class
{
var result = new List<T>();
if (typeof(T) == typeof(string))
{
foreach (var givenObject in givenObjects)
{
var instance = givenObject.ToString(); // Your custom conversion to string.
result.Add((T)(object)instance);
}
}
else
{
// Proceed as before
}
return result;
}
Incidentally, you are adding an instance of T to result for every property of T that matches a property name in U and for every item in givenObjects. I.e. if givenObjects is a list of length 1 and T is a class with 10 matching properties, result could end up with 10 entries. This looks wrong. Also, you need to watch out for indexed properties.
As an alternative to this approach, consider using Automapper, or serializing your List<U> to JSON with Json.NET then deserializing as a List<T>.
I have a class which I'm trying to run a deep copy on. One of the members of this class is 'MeshContainers' which is an instance of MeshContainerCollection.
MeshContainerCollection<> inherits from my SceneObjectCollection<> class which inherits from List<>
What I noticed is that the source object has 1 item inside the meshcontainercollection while the cloned object has 0.
When stepping through the DeepCopy process I noticed that when I try to get the fields for MeshContainerCollection, it doesn't find any.
Now MeshContainerCollection doens't have any direct fields (only inherited fields) so I thought that was the problem.
But I use:
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
Which (afaik) should also return the private inherited members.
I have looked through the existing BindingFlags but haven't been able to figure out if there is another BindingFlag I should use to get the inherited private fields.
Could someone tell me how I can manage to do a REAL deep copy?
Deep Copy method I'm using:
private static object Process(object obj)
{
if (obj == null)
return null;
Type type = obj.GetType();
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(Process(array.GetValue(i)), i);
}
return Convert.ChangeType(copied, obj.GetType());
}
else if (type.IsClass)
{
object toret = FormatterServices.GetUninitializedObject(obj.GetType());
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object fieldValue = field.GetValue(obj);
if (fieldValue == null)
continue;
field.SetValue(toret, Process(fieldValue));
}
return toret;
}
else
throw new ArgumentException("Unknown type");
}
EDIT1: I prefer not to do this by serialization but by reflection.
As mentioned in GetFields documentation,
private fields on base classes are not returned.
Try this method instead:
public static IEnumerable<FieldInfo> GetAllFields(this Type type)
{
IEnumerable<FieldInfo> fields = type.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (type.BaseType == null)
return fields;
else
return GetAllFields(baseType).Concat(fields);
}
(you might want to rewrite it to avoid all the enumerables and concatenations, but you get the idea)
one of the ways that you could achieve this is by serializing the object and then deserializing it back.. write a function to do the same..
FYI, your class needs to be marked [Serializable] for this..
there are some libraries out there that do the same.. Copyable is one of them.. I would suggest not to try and reinvent the wheel rather build up on this library as there are too many edge conditions to handle when you deep copy.. may be you can submit patches to the author too..
I am using the C# GetPropertymethod using reflection.
obj.GetType().GetProperty("columnName")
However I cannot guarantee the exact casing of the column name as it is being based in from an external source. It maybe ColumnName or columnname
I was thinking if I could just force the string column name to uppercase, but how would I then deal with the Property on the object itself? The getProperty method looks like it needs to be the EXACT casing?
You can use
var prop = GetProperty("columnname",
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.IgnoreCase);
Note that you'll still need the Instance and Public bit (assuming that this is a public instance property) as otherwise it won't find anything.
You can ignore the case when looking up the property.
GetProperty(fieldname, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
You can always combine reflection with some Linq magic, like this:
var property = typeof (MyType).GetProperties()
.Where(p => p.Name.Equals("MyProperty", StringComparison.InvariantCultureIgnoreCase));
Try:
var yourprop = from x in obj.GetType().GetProperties()
where x.Name.ToUpper() == "a column name".ToUpper()
select x;
I have a class:
class A {
public string a = "A-val" , b = "B-val";
}
I want to print the object members by reflection
//Object here is necessary.
Object data = new A();
FieldInfo[] fields = data.GetType().GetFields();
String str = "";
foreach(FieldInfo f in fields){
str += f.Name + " = " + f.GetValue(data) + "\r\n";
}
Here is the desired result:
a = A-val
b = B-val
Unfortunately this did not work. Please help, thanks.
Once fixed to get rid of the errors (lacking a semi-colon and a bad variable name), the code you've posted does work - I've just tried it and it showed the names and values with no problems.
My guess is that in reality, you're trying to use fields which aren't public. This code:
FieldInfo[] fields = data.GetType().GetFields();
... will only get public fields. You would normally need to specify that you also want non-public fields:
FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
(I hope you don't really have public fields, after all...)
Remember when you write fields like :
public string VarName{ get; set;}
Then actually you have this code(this is what reflection see) :
private string _varName;
public string get_VarName(){
....
}
public void set_VarName(strig value){
....
}
As #Stanislav say, you must keep in mind the backing fields generated by the compiler for properties. If you want to exclude these fields you can use the following code:
FieldInfo[] fields = data.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(f => f.GetCustomAttribute<CompilerGeneratedAttribute>() == null)
.ToArray();