How can I get around casting to the FieldInfo? - c#

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.

Related

MethodInfo always null when geting Type from instance

Can someone explain me, why here I get the correct MethodInfo:
MethodInfo mi = typeof(ContextTimerMode).GetMethod(_vo.Phase, BindingFlags.Instance | BindingFlags.NonPublic);
if (mi != null)
{
mi.Invoke(this, new object[] { btns, vo });
}
While trying to get it directly from instance returns always null?:
MethodInfo mi = (this as ContextTimerMode).GetType().GetMethod(_vo.Phase, BindingFlags.Instance | BindingFlags.NonPublic);
// mi always null
if (mi != null)
{
mi.Invoke(this, new object[] { btns, vo });
}
The code above is from ContextTimerMode.
this is a class that has ContextTimerMode as base class;
Actually I couldn't find a reason why it returns a null for sometime as I was using second method and I was debugging and making sure _vo.Phase string has correct name of method so I tried first method and it worked out.
Also when debugging this was showing that this is instance not of ContextTimerMode but a type that has a base of ContextTimerMode - so that is why I tried with (this as ContextTimerMode).GetType()...
That is because even if you do this:
(this as ContextTimerMode).GetType()
resulting type will not be ContextTimerMode, but will be the type inherited from ContextTimerMode (so, actual type of this, same as if you did this.GetType()). GetType() always returns actual type, even if you use it on variable declared as some base type. You are trying to get private, instance method of that type. Your inherited type really does not contain this method, so GetMethod correctly returns null.
If you want to work around this, you can manually walk hierarchy, like this:
static MethodInfo GetMethod(Type type, string methodName, BindingFlags flags) {
var mi = type.GetMethod(methodName, flags);
if (mi != null)
return mi;
if (type.BaseType != null)
return GetMethod(type.BaseType, methodName, flags);
return null;
}
The this keyword is redundant. You can just use GetType() internally and it will refer to your class.
_vo.Phase
must be the correct case and you don't need BindingFlags.Instance. I would remove BindingFlags.NonPublic as well and change the method access modifier to public to see if GetMethod() can actually find it.
You can always use GetMethods() to enumerate the available methods in the class. Maybe even use a linq query to get the MethodInfo object you want.

Activator.CreateInstance with string

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>.

My deep copy isn't doing a real deep copy

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..

Reflection class to get all properties of any object

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.

(.net) How to check if a given variable is defined with an attribute

I'd like to know if my textBox1 variable has the ABCAttribute. How can I check this?
You need a handle to the class (type) in which textBox1 exists:
Type myClassType = typeof(MyClass);
MemberInfo[] members = myClassType.GetMember("textBox1",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if(members.Length > 0) //found a member called "textBox1"
{
object[] attribs = members[0].GetCustomAttributes(typeof(ABCAttribute));
if(attribs.Length > 0) //found an attribute of type ABCAttribute
{
ABCAttribute myAttrib = attribs[0] as ABCAttribute;
//we know "textBox1" has an ABCAttribute,
//and we have a handle to the attribute!
}
}
This is a bit nasty, one possibility is to roll it into an extension method, used like so:
MyObject obj = new MyObject();
bool hasIt = obj.HasAttribute("textBox1", typeof(ABCAttribute));
public static bool HasAttribute(this object item, string memberName, Type attribute)
{
MemberInfo[] members = item.GetType().GetMember(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if(members.Length > 0)
{
object[] attribs = members[0].GetCustomAttributes(attribute);
if(attribs.length > 0)
{
return true;
}
}
return false;
}
Assuming textBox1 is, well, a TextBox control, then the answer is likely, "No, it doesn't have the attribute." Attributes are assigned to a Type, not an instance of the type. You can lookup what attributes are on any TextBox that ever was, is, or will be created right now (for a particular version of the framework).
Do you mean the attributes as in:
<input class="textbox" type="text" value="search" ABC="val" name="q"/>
In that case you can look up the attribute name in the control's Attribute collection.
WebForm Textbox control Attributes collection
If you mean attributes as in:
<ValidationPropertyAttribute("Text")> _
<ControlValuePropertyAttribute("Text")> _
Public Class TextBox _
...
then as the other posters have mentioned, you will have to use Reflection to determine if the control has a particular attribute.

Categories