Cannot using GetValues and SetValues in project C# - c#

I want to convert DataRow To Object. I write 1 class to do this.
Error like this:
No overload for method 'SetValue' takes 2 arguments
No overload for method 'GetValue' takes 1 arguments
But I can't using GetValues() and SetValues(). When converting project to 4.5. It's work.
My project is set platform target is 3.5 (Obligatory - because I connect with the device must using .NET 3.5).
How to fix this?
Here my code:
public DataRowToObject(DataRow row)
{
List<PropertyInfo> listProperty = this.GetProperties();
foreach (PropertyInfo prop in listProperty)
{
if (!row.Table.Columns.Contains(prop.Name) ||
row[prop.Name] == null ||
row[prop.Name] == DBNull.Value)
{
prop.SetValue(this, null);
continue;
}
try
{
object value = Convert.ChangeType(row[prop.Name], prop.PropertyType);
prop.SetValue(this, value);
}
catch
{
prop.SetValue(this, null);
}
}
}
public virtual Hashtable GetParameters()
{
Type type = this.GetType();
List<PropertyInfo> listProperty = new List<PropertyInfo>(type.GetProperties());
Hashtable result = new Hashtable();
foreach (PropertyInfo prop in listProperty)
{
result.Add(prop.Name, prop.GetValue(this));
}
return result;
}

There is an overload for PropertyInfo.SetValue and PropertyInfo.GetValue without the indexer added in .NET 4.5.
But it's simply a matter of passing null to the indexer parameter on previous versions (using this and this overloads).
So:
prop.SetValue(this, value, null);
And
prop.GetValue(this, null);
This should work on .NET .3.5 (up to recent versions)... actually for NET 2.0 and up :-)

Related

What does SONAR Error AvoidRepetitiveCallsToPropertiesRule mean?

I have this below piece of code, which i always highlighted by SONAR as a MAJOR issue, because of violation of a rule called with the below message.
Multiple (3) calls to virtual property 'System.String System.Reflection.MemberInfo::get_Name()'.
And the rule description says
AvoidRepetitiveCallsToPropertiesRule
gendarme : AvoidRepetitiveCallsToPropertiesRule
The rule warn if virtual, or unlikely to be inline-able, property getters are called several times by a method. In most cases repetitive calls simply requires more time without any gains since the result will always be identical. You should ignore the reported defects if a different value is expected each time the property is called (e.g. calling DateTime.Now).**
private static void OverrideConfigurationValues(ConfigA configa,
ConfigB configb, ConfigC configc)
{
Type t = configa();
var properties = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var overriddenvalues = new Dictionary<string, object>();
foreach (var prop in properties)
{
var value = prop.GetValue(configa,null);
if (value != null)
{
overriddenvalues.Add(prop.Name, value);
}
}
Type b = configb.GetType();
foreach (var prop in b.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (!overriddenvalues.ContainsKey(prop.Name))
{
var value = prop.GetValue(b,null);
if (value != null)
{
overriddenvalues.Add(prop.Name, value);
}
}
}
foreach (var overriddenvalue in overriddenvalues)
{
var overriden = overriddenvalue;
foreach (var prop in configa.GetType().GetProperties().Where(prop => prop.Name == overriden.Key))
{
prop.SetValue(configa, overriddenvalue.Value,null);
}
}
}
If the SONAR is complaining about the line prop.Name which i have inside the foreach loop? How can i avoid it?
Ron Beyer's comments are proper answers to this question.
So, your code would look like this based on his comments:
...
foreach (var prop in b.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var propName = prop.Name;
if (!overriddenvalues.ContainsKey(propName))
{
var value = prop.GetValue(b,null);
if (value != null)
{
overriddenvalues.Add(propName, value);
}
}
}
...
Note that the support of Gendarme rules was dropped in the 3.0 version of the C# plugin.

Is there any other approach to set a value to a Property (of an Instance) without using Reflection?

Currently, I am using Reflection and want to know if any other way to achieve the same.
foreach (var propertyInfo in MyObject.GetType().GetProperties())
{
if (propertyInfo.CanRead)
{
if (propertyInfo.Name.Equals(fieldName))
{
propertyInfo.SetValue(MyObject, "Some value", null);
break;
}
}
}
You can use a quicker version of reflection than what you have (the loop is not necessary):
var propertyInfo = MyObject.GetType().GetProperty(fieldName);
if (propertyInfo != null && propertyInfo.CanRead)
propertyInfo.SetValue(MyObject, "Some value", null);
Beyond reflection, I believe you can emit IL code directly -- take a look at "FastMember" (although I am not sure if Silverlight can support this approach).
If all you have is a string of the property name then I don't know any better way then reflection but looping on the posted code is not efficient.
HashSet<String> properties = new HashSet<String>();
// add the properties
foreach (var propertyInfo in MyObject.GetType().GetProperties())
{
if (propertyInfo.CanRead)
{
if (properties.Contains(propertyInfo.Name))
{
propertyInfo.SetValue(MyObject, "Some value", null);
}
}
}

Checking for Nulls on DB Record Mapping

How can I check for db null values in the attached code? Please understand I am a new C# convert...
What this code does is takes a IDataReader object and converts and maps it to a strongly-typed list of objects. But what I am finding is it completely errors out when there are null columns returned in the reader.
Converter
internal class Converter<T> where T : new()
{
// Declare our _converter delegate
readonly Func<IDataReader, T> _converter;
// Declare our internal dataReader
readonly IDataReader dataReader;
// Build our mapping based on the properties in the class/type we've passed in to the class
private Func<IDataReader, T> GetMapFunc()
{
// declare our field count
int _fc = dataReader.FieldCount;
// declare our expression list
List<Expression> exps = new List<Expression>();
// build our parameters for the expression tree
ParameterExpression paramExp = Expression.Parameter(typeof(IDataRecord), "o7thDR");
ParameterExpression targetExp = Expression.Variable(typeof(T));
// Add our expression tree assignment to the exp list
exps.Add(Expression.Assign(targetExp, Expression.New(targetExp.Type)));
//does int based lookup
PropertyInfo indexerInfo = typeof(IDataRecord).GetProperty("Item", new[] { typeof(int) });
// grab a collection of column names from our data reader
var columnNames = Enumerable.Range(0, _fc).Select(i => new { i, name = dataReader.GetName(i) }).AsParallel();
// loop through all our columns and map them properly
foreach (var column in columnNames)
{
// grab our column property
PropertyInfo property = targetExp.Type.GetProperty(column.name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
// check if it's null or not
if (property != null)
{
// build our expression tree to map the column to the T
ConstantExpression columnNameExp = Expression.Constant(column.i);
IndexExpression propertyExp = Expression.MakeIndex(paramExp, indexerInfo, new[] { columnNameExp });
UnaryExpression convertExp = Expression.Convert(propertyExp, property.PropertyType);
BinaryExpression bindExp = Expression.Assign(Expression.Property(targetExp, property), convertExp);
// add it to our expression list
exps.Add(bindExp);
}
}
// add the originating map to our expression list
exps.Add(targetExp);
// return a compiled cached map
return Expression.Lambda<Func<IDataReader, T>>(Expression.Block(new[] { targetExp }, exps), paramExp).Compile();
}
// initialize
internal Converter(IDataReader dataReader)
{
// initialize the internal datareader
this.dataReader = dataReader;
// build our map
_converter = GetMapFunc();
}
// create and map each column to it's respective object
internal T CreateItemFromRow()
{
return _converter(dataReader);
}
}
Mapper
private static IList<T> Map<T>(DbDataReader dr) where T : new()
{
try
{
// initialize our returnable list
List<T> list = new List<T>();
// fire up the lamda mapping
var converter = new Converter<T>(dr);
while (dr.Read())
{
// read in each row, and properly map it to our T object
var obj = converter.CreateItemFromRow();
// add it to our list
list.Add(obj);
}
// reutrn it
return list;
}
catch (Exception ex)
{
// make sure this method returns a default List
return default(List<T>);
}
}
I just don't quite understand where the column to typed object happens in here, so I'd try to do it myself... but I just don;t know where it is.
I know this probably won't help much, but the error I am getting is:
Unable to cast object of type 'System.DBNull' to type 'System.String'.
and it happens on the
internal T CreateItemFromRow()
{
return _converter(dataReader); //<-- Here
}
Note
This does not happen if I wrap the columns in the query itself with an ISNULL(column, ''), but I am sure you can understand that this is surely not a solution
The problem lies in the line convertExp = Expression.Convert(propertyExp, property.PropertyType). You can't expect to convert DbNull value to its equivalent in framework type. This is especially nasty when your type is a value type. One option is to check if the read value from db is DbNull.Value and in case yes, you need to find a compatible value yourself. In some cases people are ok with default values of those types in C#. If you have to do this
property = value == DBNull.Value ? default(T): value;
a generic implementation would look like (as far as the foreach in your converter class goes):
foreach (var column in columns)
{
var property = targetExp.Type.GetProperty(
column.name,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (property == null)
continue;
var columnIndexExp = Expression.Constant(column.i);
var propertyExp = Expression.MakeIndex(
paramExp, indexerInfo, new[] { columnIndexExp });
var convertExp = Expression.Condition(
Expression.Equal(
propertyExp,
Expression.Constant(DBNull.Value)),
Expression.Default(property.PropertyType),
Expression.Convert(propertyExp, property.PropertyType));
var bindExp = Expression.Assign(
Expression.Property(targetExp, property), convertExp);
exps.Add(bindExp);
}
Now this does an equivalent of
property = reader[index] == DBNull.Value ? default(T): reader[index];
You could avoid the double lookup of the reader by assigning it to a variable and using its value in the conditional check. So this should be marginally better, but a lil' more complex:
foreach (var column in columns)
{
var property = targetExp.Type.GetProperty(
column.name,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (property == null)
continue;
var columnIndexExp = Expression.Constant(column.i);
var cellExp = Expression.MakeIndex(
paramExp, indexerInfo, new[] { columnIndexExp });
var cellValueExp = Expression.Variable(typeof(object), "o7thPropValue");
var convertExp = Expression.Condition(
Expression.Equal(
cellValueExp,
Expression.Constant(DBNull.Value)),
Expression.Default(property.PropertyType),
Expression.Convert(cellValueExp, property.PropertyType));
var cellValueReadExp = Expression.Block(new[] { cellValueExp },
Expression.Assign(cellValueExp, cellExp), convertExp);
var bindExp = Expression.Assign(
Expression.Property(targetExp, property), cellValueReadExp);
exps.Add(bindExp);
}
This does the conditional check this way:
value = reader[index];
property = value == DBNull.Value ? default(T): value;
This is one of the most annoying problems in dealing with datasets in general.
The way I normally get around it is to convert the DBNull value to something more useful, like an actual null or even a blank string in some cases. This can be done in a number of ways, but just recently I've taken to using extension methods.
public static T? GetValueOrNull<T>(this object value) where T : struct
{
return value == null || value == DBNull.Value ? (T?) null : (T) Convert.ChangeType(value, typeof (T));
}
A handy extension method for nullable types, so for example:
int? myInt = DataSet.Tables[0].Rows[0]["DBNullInt"].GetValueOrNull<int>();
Or a more generic one to just convert a DBNull in to a null:
public static object GetValueOrNull(this object value)
{
return value == DBNull.Value ? null : value;
}
string myString DataSet.Tables[0].Rows[0]["DBNullString"].GetValueOrNull();
You'll then get a null string, rather than trying to put a DBNull in to a string.
Hopefully that may help you a little.
As I come across this problem recently
both
Expression.TypeIs(propertyExp,typeof(DBNull));
and
Expression.Equal(propertyExp,Expression.Constant(DBNull.Value));
didn't work for me as they did increase memory allocation (which is my primary concern in this case)
here is the benchmark for both mapper approach compare to Dapper on 10K rows query.
TypeIs
and
Equal
so to fix this problem it came out that an IDataRecord is able to call "IsDBNull" to check whether the column in current reader is DBNull or not
and can be write as expression like
var isReaderDbNull = Expression.Call(paramExp, "IsDBNull", null, readerIndex);
finally, I end up with this solution
and now the performance is acceptable again.

Conditional for matching generic nullable numeric types

Given a type T, is there any way to write something equivalent of
if (typeof(T).ImplementsProperty(MaxValue))
{
return T ?? typeof(T).MaxValue;
}
else
return T;
Note that I don't need a generic type constraint on the class or method, I just need a conditional in the method body. T in this case can be any IComparable. I'm trying to get null numeric/date types to be ordered with the nulls occurring last.
Edit: Sorry there is an error in the above syntax as pointed out by Ray. It should be returning value ?? typeof(T).MaxValue given a T value or something like that. Hope thats clear.
This seems to work for me for nullable, value and reference types:
public T GetSelfOrMaxValue<T>(T value)
{
var t = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
var fi = t.GetField("MaxValue");
if (fi != null && fi.IsStatic && fi.FieldType.Equals(t))
{
return (T)fi.GetValue(null);
}
return value;
}
Is this what you wanted?
Firstly a problem. You can't return T which is a Type Parameter. It would be equivalent to return int which is invalid.
But you can see if T has a MaxValue property and call it if it does. The below code checks for the static property called MaxValue and calls it (and assumes it's an int).
Type type = typeof (T);
var propInfo = type.GetProperty("MaxValue", BindingFlags.Static | BindingFlags.Public);
if (propInfo != null)
return (int)propInfo.GetValue(null, null);
I assume you want something like this:
public static T GetValueOrMax<T>(T value) where T:IComparable
{
if (value != null)
return value;
Type type = typeof (T);
var propInfo = type.GetProperty("MaxValue", BindingFlags.Static | BindingFlags.Public);
if (propInfo != null)
return (T)propInfo.GetValue(null, null);
return value;
}
But this will have it's own problems, if you pass an int in, it will never be null and it will always return value. If you pass a nullable int in, then it won't implement MaxValue (actually you can't pass a nullable int, since it doesn't implement IComparable).
A where clause of where T:class, IComparable may be the most appropriate.
Another option would be to change the check at the beginning to be
if (value != default(T))
return value
But then passing 0 would return the MaxValue not 0, which may not be what you want.

How to invoke System.Linq.Enumerable.Count<> on IEnumerable<T> using Reflection?

I have a bunch of IEnumerable Collections which exact number and types is subject of frequent changes (due to automatic code generation).
It looks something like this:
public class MyCollections {
public System.Collections.Generic.IEnumerable<SomeType> SomeTypeCollection;
public System.Collections.Generic.IEnumerable<OtherType> OtherTypeCollection;
...
At runtime i want to determine each Type and it's count without having to rewrite the code after every code generation. So i am looking for a generic approach using reflection. The result i am looking for is something like:
MyType: 23
OtherType: 42
My problem is that i can't figure how to invoke the Count method properly. Here is what i have so far:
// Handle to the Count method of System.Linq.Enumerable
MethodInfo countMethodInfo = typeof(System.Linq.Enumerable).GetMethod("Count", new Type[] { typeof(IEnumerable<>) });
PropertyInfo[] properties = typeof(MyCollections).GetProperties();
foreach (PropertyInfo property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType.IsGenericType)
{
Type genericType = propertyType.GetGenericTypeDefinition();
if (genericType == typeof(IEnumerable<>))
{
// access the collection property
object collection = property.GetValue(someInstanceOfMyCollections, null);
// access the type of the generic collection
Type genericArgument = propertyType.GetGenericArguments()[0];
// make a generic method call for System.Linq.Enumerable.Count<> for the type of this collection
MethodInfo localCountMethodInfo = countMethodInfo.MakeGenericMethod(genericArgument);
// invoke Count method (this fails)
object count = localCountMethodInfo.Invoke(collection, null);
System.Diagnostics.Debug.WriteLine("{0}: {1}", genericArgument.Name, count);
}
}
}
If you insist on doing it the hard way ;p
Changes:
how you obtain countMethodInfo for a generic method
the arguments to Invoke
Code (note obj is my instance of MyCollections):
MethodInfo countMethodInfo = typeof (System.Linq.Enumerable).GetMethods().Single(
method => method.Name == "Count" && method.IsStatic && method.GetParameters().Length == 1);
PropertyInfo[] properties = typeof(MyCollections).GetProperties();
foreach (PropertyInfo property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType.IsGenericType)
{
Type genericType = propertyType.GetGenericTypeDefinition();
if (genericType == typeof(IEnumerable<>))
{
// access the collection property
object collection = property.GetValue(obj, null);
// access the type of the generic collection
Type genericArgument = propertyType.GetGenericArguments()[0];
// make a generic method call for System.Linq.Enumerable.Count<> for the type of this collection
MethodInfo localCountMethodInfo = countMethodInfo.MakeGenericMethod(genericArgument);
// invoke Count method (this fails)
object count = localCountMethodInfo.Invoke(null, new object[] {collection});
System.Diagnostics.Debug.WriteLine("{0}: {1}", genericArgument.Name, count);
}
}
}
That is going to involve some MakeGenericMethod - and a lot of reflection generally. Personally, I would be tempted to just simplify by ditching the generics in this case:
public static int Count(IEnumerable data) {
ICollection list = data as ICollection;
if(list != null) return list.Count;
int count = 0;
IEnumerator iter = data.GetEnumerator();
using(iter as IDisposable) {
while(iter.MoveNext()) count++;
}
return count;
}
You can cast to the non-generic IEnumerable trivially, even if fetching via reflection.
By now, the question has been answered, but I'd like to present you a trimmed down — and I think, rather trivial version — of the "calling a generic extension method", which can be used to invoke Count reflectively:
// get Enumerable (which holds the extension methods)
Type enumerableT = typeof(Enumerable);
// get the Count-method (there are only two, you can check the parameter-count as in above
// to be certain. Here we know it's the first, so I use the first:
MemberInfo member = enumerableT.GetMember("Count")[0];
// create the generic method (instead of int, replace with typeof(yourtype) in your code)
MethodInfo method = ((MethodInfo) member).MakeGenericMethod(typeof(int));
// invoke now becomes trivial
int count = (int)method.Invoke(null, new object[] { yourcollection });
The above works, because you don't need to use the generic type of IEnumerable<> to be able to invoke Count, which is an extension of Enumerable and takes an argument of IEnumerable<T> as first param (it's an extension), but you don't need to specify that.
Note that, from the reading of your question, it seems to me that you should actually use generics for your types, which adds type safety back into your project and still allows you to use Count or whatever. After all, the one thing that's certain is that all are Enumerable, right? If so, who needs reflection?
var count = System.Linq.Enumerable.Count(theCollection);
Edit: you say it's generated though, so can you not just generate a properties with calls to Count()?
public class MyCollections
{
public System.Collections.Generic.IEnumerable<SomeType> SomeTypeCollection;
public System.Collections.Generic.IEnumerable<OtherType> OtherTypeCollection;
public int CountSomeTypeCollection
{
get { return this.SomeTypeCollection.Count(); }
}
...

Categories