Invalid cast from System.Int32 to Nullable in case of Enum properties - c#

I have the following static method:
public static cols Parse(string[] inCols, int[] dat)
{
cols c = new cols();
PropertyInfo[] properties = typeof(cols).GetProperties();
for (int i = 0; i < inCols.Length; i++)
{
PropertyInfo prop = properties.Single(a => a.Name == inCols[i]);
var t = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
var safeValue = Convert.ChangeType(dat[i], t);
prop.SetValue(c, safeValue);
}
return c;
}
Here, the properties of "cols" class are nullable Enum types.
The method has two incoming parameters (inCols and dat). The inCols contains the properties names as string, the dat contains their values as int.
The method's task would be to based on the method's name, it assigns the proper values the the nullable enum type.
I receive the following error message: System.InvalidCastException: 'Invalid cast from 'System.Int32' to '<my enum type>'.'
This is strange, because the value should be 0, which is fine for the enum becuase it is its first value.
Does any of you have any idea?
Thanks!
Gabor

Because you're dealing only with Enums, you may simply change your code to this:
var safeValue = Enum.ToObject(t, dat[i]);

Related

Cannot convert from 'System.Collections.IList' to 'System.Collections.Generic.IEnumerable<T>'

Using C# 10 I am trying to convert an IEnumerable<String>? to an IEnumerable<T>:
IEnumerable<String>? inputs = getValues();
if (inputs is null)
return false;
Type type = typeof(List<>).MakeGenericType(typeof(T));
IList? outputs = (IList?)Activator.CreateInstance(type);
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
if (converter is null || outputs is null || !converter.CanConvertFrom(typeof(String)))
return false;
foreach (String input in inputs) {
if (converter.IsValid(input))
outputs.Add(converter.ConvertFromString(input));
}
var texpression = new TExpression<T>(outputs);
I am getting an error on last line even if I use outputs.ToList():
Cannot convert from 'System.Collections.IList' to 'System.Collections.Generic.IEnumerable<T>'
The TExpression constructor is:
public TExpression(IEnumerable<T> values) {
Values = values;
}
I tried to change the types of my conversion code but I always end with an error somewhere.
How can I fix this so I can use the constructor without changing the constructor?
Update
Using the following:
IList<T> outputs = (IList<T>)Activator.CreateInstance(type);
...
foreach (string input in inputs) {
if (converter.IsValid(input))
outputs.Add((T)converter.ConvertFromString(input));
}
I get the warning (I am using <Nullable>enable</Nullable>):
Converting null literal or possible null value to non-nullable type.
T can be a nullable type (Int32?) or a non nullable type (Int32).
I could change the code line to:
T? output = (T?)converter.ConvertFromString(input);
This fixes the warning but is it correct?
What if T is a non nullable type?
Since you actually now the type of collection you can use it:
IList<T> outputs = (IList<T>)Activator.CreateInstance(type);
...
foreach (string input in inputs) {
if (converter.IsValid(input))
outputs.Add((T)converter.ConvertFromString(input)); // here also
}

Foreach enum values without casting

I have to cast enum but I want this to be as generic as possbile. How can I replace the Cast<XX>() part with propertyType?
foreach (var prop in MainType.GetProperties().Where(x => x.PropertyType.IsEnum))
{
var x = new { name = prop.Name, values = new List<object>() };
foreach (var v in Enum.GetValues(prop.PropertyType).Cast<XX>())
x.values.Add(new { p = v.GetAttribute<DescriptionAttribute>().Description,
c = v.GetAttribute<DefaultValueAttribute>().Value });
o.Add(x);
}
public static TAttribute GetAttribute<TAttribute>(this Enum value) where TAttribute : Attribute
{
var type = value.GetType();
var name = Enum.GetName(type, value);
return type.GetField(name)
.GetCustomAttributes(false)
.OfType<TAttribute>()
.SingleOrDefault();
}
public enum JobApplicationState : short
{
[Description("Active")]
[DefaultValue(typeof(string), "bg-primary text-highlight")]
Active = 1,
[Description("Passive")]
[DefaultValue(typeof(string), "bg-grey text-highlight")]
Passive = 2,
[Description("Rejected")]
[DefaultValue(typeof(string), "bg-danger text-highlight")]
Rejected = 3,
[Description("Accepted")]
[DefaultValue(typeof(string), "bg-success text-highlight")]
Accepted = 4
}
THIS WORKED!
foreach (MemberInfo m in prop.PropertyType.GetFields())
{
if (m.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault() != null && m.GetCustomAttributes(typeof(DefaultValueAttribute), true).FirstOrDefault() != null)
{
x.values.Add(
new
{
p = ((DescriptionAttribute)m.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault()).Description,
c = ((DefaultValueAttribute)m.GetCustomAttributes(typeof(DefaultValueAttribute), true).FirstOrDefault()).Value
});
}
}
You should realize that an enum is nothing more than a named wrapper around an integral value. I've described some details on how enums work here: Cast int to enum in C# .
The question here is to get attributes values from an enum. As you might imagine, this question is about getting attributes from the type, not about getting attributes from the value (there's no such thing). Still, if you call a method like void Foo<T>(T myEnum), the type T will hold all the necessary info, even though 'in real life' the value of myEnum is passed around as an integral type.
From this you can also deduce that you're actually looking for the attributes of the MemberInfo's of T, since you're looking for the members of the type (e.g. the enum). Again, all the details are in my post on how enums work. Hence the answer:
foreach (MemberInfo m in prop.PropertyType.GetFields())
{
// use m.GetAttribute(...)
}
Why donĀ“t you simply cast to Enum:
foreach (var v in Enum.GetValues(prop.PropertyType).Cast<Enum>())
Now you can call your extension-method on every element within the returned list.
v.GetAttribute<MyType>()

Get number of enum values from instance

I'm trying to loop through all of the enums in an object and for each enum, I need to get the number of values for its particular type. So far I have the following code:
var enumProps = testObj.GetType().GetProperties().Where(p => p.PropertyType.IsEnum);
foreach (var prop in enumProps)
{
var propType = prop.GetType();
var valueCount = Enum.GetValues(typeof(propType)).Length; // <-- error
}
The problem is that when I pass propType to typeof, I get the following error:
propType is a variable but used as a type.
Anyone see where I'm going wrong here?
GetType produces the type of prop, which is fixed (i.e. PropertyInfo reflection class). You need to use PropertyType member, like this:
foreach (var prop in enumProps) {
var propType = prop.PropertyType;
var valueCount = Enum.GetValues(propType).Length;
}
Demo.
Note that typeof operator is not necessary, because propType is already a System.Type that you need.

Object of type 'System.Double' cannot be converted to type 'System.Int32'

I am facing problem in my code, its telling system.int32 cant not be converted to system.double, here is my code
I have an object with 4 string variables and 2 integer variables.
public class MyObject
{
public int id;
public string name1;
public string name2;
public string name3;
public string name4;
public int id2;
}
/*Converts DataTable To List*/
public static List<TSource> ToList<TSource>(this DataTable dataTable) where TSource : new()
{
var dataList = new List<TSource>();
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
var objFieldNames = (from PropertyInfo aProp in typeof(TSource).GetProperties(flags)
select new { Name = aProp.Name, Type = Nullable.GetUnderlyingType(aProp.PropertyType) ?? aProp.PropertyType }).ToList();
var dataTblFieldNames = (from DataColumn aHeader in dataTable.Columns
select new { Name = aHeader.ColumnName, Type = aHeader.DataType }).ToList();
var commonFields = objFieldNames.Intersect(dataTblFieldNames).ToList();
foreach (DataRow dataRow in dataTable.AsEnumerable().ToList())
{
var aTSource = new TSource();
foreach (var aField in objFieldNames)
{
PropertyInfo propertyInfos = aTSource.GetType().GetProperty(aField.Name);
propertyInfos.SetValue(aTSource, dataRow[aField.Name], null);
}
dataList.Add(aTSource);
}
return dataList;
}
In my objectfieldname variable i am getting all the variable with right data type, but in dataTblFieldNames variable its converting int to double, so i am facing problem in propertyinfos in foreach loop its saying
Object of type 'System.Double' cannot be converted to type 'System.Int32'.?
Any one help me to fix this please?
You can use Convert.ChangeType method:
Convert.ChangeType(dataRow[aField.Name], propertyInfos.PropertyType)
It will try some numeric conversions (like your conversion from double to int, a change in binary representation from floating point to integer (2's complement)) and some formatting/parsing to/from string.
You have find property type before assigning value and you have to also cast value to the type required because you can not directly assign double type to int type.
if (propertyInfos.PropertyType == typeof(int))
{
propertyInfos.SetValue(aTSource, Convert.ToInt32(dataRow[aField.Name]), null);
}
Your input dataRow[aField.Name] is of type System.Double while the field you want to assign to is of type System.Int32. But Visual Studio already told you so loud and clear.
I cannot tell you what to do because I don't know what you want to do. Truncate the double by casting? Round it up or down? Maybe it's the wrong field altogether? we don't know. You decide.
Considering the fact that it's pretty unlikely you came up with the above code and still did not understand the error, maybe it's a good idea to either get a full nights sleep and a good coffee or ask the one who originally wrote this code.

Object does not match target type with SetValue and enum

I tried adapting this tutorial from CodeProject to try and change a dynamic which will in this case be an int to a simple Enum.
If we define the Enum like so:
public Enum MyEnum { Zero = 0, One = 1, Two = 2 }
And the contents of a method to set the value of a MyObject class which contains an MyEnum:
var baseType = propertyInfo.PropertyType.BaseType; //`propertyInfo` is the `PropertyInfo` of `MyEnum`
var isEnum = baseType != null && baseType == typeof(Enum); //true in this case
dynamic d;
d = GetInt();
//For example, `d` now equals `0`
if (isEnum)
d = Enum.ToObject(propertyInfo.PropertyType, (int)d);
//I can see from debugger that `d` now equals `Zero`
propertyInfo.SetValue(myObject, d);
//Exception: Object does not match target type
Any ideas as to why this is happening?
"Object does not match target type" indicates that myObject is not an instance of the type that propertyInfo was obtained from. In other words, the property you are trying to set is on one type, and myObject is not an instance of that type.
To illustrate:
var streamPosition = typeof(Stream).GetProperty("Position");
// "Object does not match target type," because the object we tried to
// set Position on is a String, not a Stream.
streamPosition.SetValue("foo", 42);

Categories