IsEnum does not recognise enum - c#

My code is .Net 4.0 and I am trying to understand some legacy code I now work with. I can't change it at the moment and i'm sure this code has worked before my time. It needs to make an enum from strings, but the type is not recognized as an enum.
EDIT
I now realize the enum property is actually nullable. So it is a NetType? How can I convert that into an enum if it has a value?
When I debug and see the type that is being checked on the enum, this is what I see:
FullName = System.Nullable1[[AppName.Model.NetType, AppName.Model,
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]
Name = Nullable1
This is the enum:
public enum NetType
{
ChoiceOne = 1,
ChoiceTwo = 2
}
Main code, simplified for clarity:
var property = typeof(MainClass).GetProperty("NetType");
var value = GetValue(property.PropertyType, "ChoiceOne");
private object GetValue(Type type, string valueString)
{
if (type.IsEnum)// Why false?
return Enum.Parse(type, valueString);
if (type == typeof (Int32))
return Int32.Parse(valueString);
return valueString;
}

Another option is to use Nullable.GetUnderlyingType() to check to see if it's a nullable enum first. If it is, use the underlying enum; if it's not, do your checks as you normally did.
private object GetValue(Type type, string valueString)
{
// If Nullable.GetUnderlyingType() returns null, it's not nullable
// and you can default to type.
var enumCandidiate = Nullable.GetUnderlyingType(type) ?? type;
if (enumCandidiate.IsEnum)
return Enum.Parse(enumCandidiate, valueString);
if (type == typeof (Int32))
return Int32.Parse(valueString);
return valueString;
}
Here was my test script (using RoslynPad, hence the Dump() calls).
var val = GetValue(typeof(NetType), "ChoiceOne");
val.Dump();
val = GetValue(typeof(NetType?), "ChoiceOne");
val.Dump();

Try this:
var type = property.PropertyType;
object value;
if (type.IsEnum)
{
value = GetValue(type, "ChoiceOne");
}
else if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>) &&
type.GetGenericArguments()[0].IsEnum)
{
value = GetValue(type.GetGenericArguments()[0], "ChoiceOne");
}
It should work for both NetType and NetType?.

Related

Comparing two equal vars return false

Some background to understand the code. I have an MVC application, all my models implement IModel. IModel just enforces to have an int Id property.
The following method "updates" an instances of a model with the data available in a viewmodel. For each property of the viewmodel it checks if a corresponding property exists in the model, if it does It updates the value in the model with those of the viewmodel, if the values are different.
At the last point it goes wrong. The statement : OldValue != NewValue always returns true, even if f.e. both are integers, 1. Why ?
public static Boolean UpdateIfChanged<M, VM>(this M Model, VM ViewModel) where M : IModel
{
Boolean HasUpdates = false;
Type Mtype = typeof(M);
PropertyInfo[] MProperties = Mtype.GetProperties(BindingFlags.Public | BindingFlags.Instance);
Type VMtype = typeof(VM);
PropertyInfo[] VMProperties = VMtype.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var VMProperty in VMProperties)
{
if (!VMProperty.PropertyType.GetInterfaces().Any(x => x.Name == typeof(IModel).Name)
&& MProperties.Any(x => x.Name == VMProperty.Name)
&& Mtype.GetProperty(VMProperty.Name).PropertyType == VMProperty.PropertyType )
{
var OldValue = Mtype.GetProperty(VMProperty.Name).GetValue(Model);
var NewValue = VMtype.GetProperty(VMProperty.Name).GetValue(ViewModel);
if (NewValue != null)
{
if (OldValue == null)
{
Mtype.GetProperty(VMProperty.Name).SetValue(Model, NewValue);
HasUpdates = true;
}
else
{
if (OldValue != NewValue)
{
Mtype.GetProperty(VMProperty.Name).SetValue(Model, NewValue);
HasUpdates = true;
}
}
}
}
}
return HasUpdates;
}
The problem here is that OldValue and NewValue are objects at compile time, not int, and therefore the ==/!= operators call the ones defined by the object class, because all operators are static. The object operators check for referential equality, not logical equality, and thus only check if the two arguments are exactly the same object (the same pointer in C++)
To get around this, you have several options
As Tigran mentioned, type cast the values coming out, so you end up using the operator defined in int instead of object
Call object.Equals(OldValue, NewValue), which checks for null and then calls the virtual Object.Equals(object o), which thus will call the function defined in the actual class/struct of the calling object (in this case int)
your GetValue(..) call returns boxed integer object, so reference type.
Hence your code:
//OldValue and NewValue are Object types and NOT integers !
if (OldValue != NewValue)
compares references and not values.
You didn't notice that as you are using var keyword, which "hides" concrete type.
To correctly overcome this issue, may do like:
....
var OldValue = (int)Mtype.GetProperty(VMProperty.Name).GetValue(Model); //cast to int
var NewValue = (int)VMtype.GetProperty(VMProperty.Name).GetValue(ViewModel);//cast to int
....
Try this if (OldValue.ToString() != NewValue.ToString()). Or if OldValue/NewValue are int-s: if ((int)OldValue != (int)NewValue)
A better syntax would be:
if (!Equals(OldValue, NewValue))

Default value and linq

Why this simple code doesnt work?
var abc = new[]{1,2,3,4}.Select(x => default(typeof(x)));
i expect something like array of zeros but get compiler error. So how i can default values in lambda expressions?
In my real application i have meta class with type Type
public class FieldInfo
{
public Type type
}
I get IEnumerable<FieldInfo> as parameter to my method and want return an array of default values for each type (object[])
This is the problem:
typeof(x)
You're using the typeof operator as if it's a method call, taking a value. It's not. It needs a compile-time type name or type parameter (or unbound type such as Dictionary<,>, or void).
The same is try with the default operator.
So that's what's wrong - but without knowing what you're trying to achieve, we can't actually advise you on how to fix it. You might just want something like this:
public static IEnumerable<T> SelectDefault<T>(this IEnumerable<T> source)
{
return source.Select(x => default(T));
}
Then this:
var abc = new[]{1,2,3,4}.SelectDefault().ToArray();
... would give you an int[] with all values zero.
EDIT: Now we have more information, it's easier to provide what you want, which is basically a method to get the default value from a Type, boxing as appropriate:
public static object GetDefaultValue(Type type)
{
// Non-nullable value types should be boxed, basically
if (type.IsValueType && Nullable.GetUnderlyingType(type) == null)
{
// Not the swiftest approach in the world, but it works...
return Activator.CreateInstance(type);
}
// Everything else defaults to null
return null;
}
So you'd have something like:
var defaults = fields.Select(field => GetDefaultValue(field.type));
(Where field is a FieldInfo as per the question - I'm deliberately not calling GetType() here.)
Do you mean this?
var abc = new[]
{
1, 2, 3, 4
}
.Select(x = > {
var xType = x.GetType();
if (xType.IsValueType)
{
return Activator.CreateInstance(xType);
}
else
{
return null;
}
})
You can't get the default value at runtime this way, default() and typeof() are compile time features. But you can try this suggestion. It uses Activator.CreateInstance to get the default value for a value type at runtime.
The compiler needs a compile-time type:
var abc = new[]{1,2,3,4}.Select(x => default(Int32));
will generate all 0's. I have no idea what you are trying to achieve with this, though, because all this does is return an empty array with the default value.

how to cmpare same types where IsGenericTypeDefinition is deff

I have a issue where I want to identify if a object is of type KeyValuePair<,>
when I compare in if:
else if (item.GetType() == typeof(KeyValuePair<,>))
{
var key = item.GetType().GetProperty("Key");
var value = item.GetType().GetProperty("Value");
var keyObj = key.GetValue(item, null);
var valueObj = value.GetValue(item, null);
...
}
this is false as IsGenericTypeDefinition is different for them.
Can someone explain me why this is happening and how to solve the this issue in correct way (I mean not comparing Names or other trivial fields.)
THX in advance!
item.GetType() == typeof(KeyValuePair<,>)
The above will never work: it is impossible to make an object of type KeyValuePair<,>.
The reason is that typeof(KeyValuePair<,>) does not represent a type. Rather, it is a generic type definition - a System.Type object used to examine structures of other generic types, but not themselves representing a valid .NET type.
If an item is, say, a KeyValuePair<string,int>, then item.GetGenericTypeDefintion() == typeof(KeyValuePair<,>)
Here is how you can modify your code:
...
else if (item.IsGenericType() && item.GetGenericTypeDefintion() == typeof(KeyValuePair<,>)) {
...
}
Found this piece of code, give it a try:
public bool IsKeyValuePair(object o)
{
Type type = o.GetType();
if (type.IsGenericType)
{
return type.GetGenericTypeDefinition() != null ? type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>) : false;
}
return false;
}
Source:
http://social.msdn.microsoft.com/Forums/hu-HU/csharpgeneral/thread/9ad76a19-ed9c-4a02-be6b-95870af0e10b

Getting 'basic' datatype rather than weird nullable one, via reflection in c#

My basic need is to get the datatypes from an anonymous type generated from a LINQ to SQL query.
I have a piece of code (cleverer than I could write, since I haven't really delved into reflection) which returns the datatypes from an anonymous types, and works perfectly for the elements marked 'not nullable' in the linq2sql properties. So, if I have a string it will return as System.String. However, when the element is nullable I end up with the 'full name' of it being:
{Name = "Nullable1" FullName = "System.Nullable1[[System.Decimal, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}
All I want to extract is the System.Decimal type in such a case (and in cases of strings or whatever, I'd just want System.String). I've looked through the properties and can't find anything that seems to store this.
private static Dictionary<string, Type> GetFieldsForType<T>(IEnumerable<T> data)
{
object o = data.First();
var properties = o.GetType().GetProperties();
return properties.ToDictionary(property => property.Name, property => property.PropertyType);
}
The LINQ query (which I don't think really matters here):
var theData = from r in db.tblTestEdits select new { myitem = r.textField, mydecimal = r.decimalField };
I found this link that seems to try to address a similar thing.
http://ysgitdiary.blogspot.com/2010/02/blog-post.html
Though it seems to return a "string" of what the type is rather than the actual type, which is what I need. Not sure how to convert such a thing.
Many thanks all.
private static Type GetCoreType(Type type)
{
if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>))
return Nullable.GetUnderlyingType(type);
else
return type;
}
You want something like this maybe
Type targetType;
bool isNullable;
// Do we have a nullable type?
if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
isNullable = true;
targetType = type.GetGenericArguments()[0];
}
else
{
isNullable = false;
targetType = type;
}

Extension Method for copying properties form object to another, with first attempt

I'm trying to write an extension method that I can use to copy values from one object property to another object of a different type, as long as the property names and types match exactly.
This is what I have:
public static T CopyFrom<T>(this T toObject, object fromObject)
{
var fromObjectType = fromObject.GetType();
var fromProperties = fromObjectType.GetProperties();
foreach (PropertyInfo toProperty in toObject.GetType().GetProperties())
{
PropertyInfo fromProperty = fromObjectType.GetProperty(toProperty.Name);
if (fromProperty != null) // match found
{
// check types
var fromType = fromProperty.PropertyType.UnderlyingSystemType;
var toType = toProperty.PropertyType.UnderlyingSystemType;
if (toType.IsAssignableFrom(fromType))
{
toProperty.SetValue(toObject, fromProperty.GetValue(fromObject, null), null);
}
}
}
return toObject;
}
This is working great for non boxed types, but Nullable<T> returns false when I call
toType.IsAssignableFrom(fromType)
because its type is Nullable<T> and is not the underlying type T.
I read here that GetType() should unbox the Nullable<T> so it returns T but if I call that on PropertyInfo.PropertyType I get ReflectedMemberInfo and not the type T im looking for.
I think I'm missing something obvious here, so I thought I would throw it open to SO to get some advice.
Anyone have any ideas?
UPDATE: Here is the final method for anyone searching for this.
public static T CopyFrom<T>(this T toObject, object fromObject)
{
var fromObjectType = fromObject.GetType();
foreach (PropertyInfo toProperty in toObject.GetType().GetProperties())
{
PropertyInfo fromProperty = fromObjectType.GetProperty(toProperty.Name);
if (fromProperty != null) // match found
{
// check types
var fromType = Nullable.GetUnderlyingType(fromProperty.PropertyType) ?? fromProperty.PropertyType;
var toType = Nullable.GetUnderlyingType(toProperty.PropertyType) ?? toProperty.PropertyType;
if (toType.IsAssignableFrom(fromType))
{
toProperty.SetValue(toObject, fromProperty.GetValue(fromObject, null), null);
}
}
}
return toObject;
}
You're looking for Nullable.GetUnderlyingType.
For example:
toType = Nullable.GetUnderlyingType(toType) ?? toType;

Categories

Resources