Question about indexers and/or generics - c#

how is it possible to know whether an object implements an indexer?, I need to share a logic for a DataRow and a IDataReader, but they don't share any interface.
I tried also with generics but don't know what restriction should I put on the where clause.
public class Indexer {
// myObject should be a DataRow or a IDataReader
private object myObject;
public object MyObject {
get { return myObject; }
set { myObject = value; }
}
// won't compile, myObject has no indexer
public object this[int index] {
get { return myObject[index]; }
set { myObject[index] = value; }
}
public Indexer(object myObject) {
this.myObject = myObject;
}
}
public class Caller {
void Call() {
DataRow row = null;
IDataReader reader = null;
var ind1 = new Indexer(row);
var ind2 = new Indexer(reader);
var val1 = ind1[0];
var val2 = ind1[0];
}
}

You'd need to declare an interface with an indexer property, use that interface as the constraint, and the type argument class would need to implement that interface in order to satisfy the constraint.
As you don't control the classes you want to use, that wouldn't work.
An alternative is to make the Indexer class take the get/set operations as separate parameters:
public class Indexer {
private Func<int, object> getter;
private Action<int, object> setter;
public object this[int index]
{
get { return getter(index); }
set { setter(index, value); }
}
public Indexer(Func<int, object> g, Action<int, object> s)
{
getter = g;
setter = s;
}
}
public static class IndexerExtensions
{
public static Indexer ToIndexer(this DataRow row)
{
return new Indexer(n => row[n], (n, v) => row[n] = v);
}
public static Indexer ToIndexer(this IDataReader row)
{
return new Indexer(n => row[n], (n, v) => row[n] = v);
}
}
You could then do this:
DataRow row = null;
IDataReader reader = null;
var ind1 = row.ToIndexer();
var ind2 = reader.ToIndexer();
var val1 = ind1[0];
var val2 = ind1[0];

You could make your Indexer an abstract base class, with two subclasses, one for DataRow, and one for IDataReader.
To make it easier to use, 2 factory methods could exist, such as:
var ind1 = Indexer.CreateFromDataRow(row);
var ind2 = Indexer.CreateFromIDataReader(reader);
They could create a specific base class for that type, with it's own logic for handling the indexing.
This avoids the overhead of checking types constantly for every get/set call (at the cost of a single virtual property instead of a standard property).

get {
DataRow row = myObject as DataRow;
if (row != null)
return row[index];
IDataReader reader = myObject as IDataReader;
if (reader != null)
return reader[index];
}
and use the same logic for set{}

Related

How to get concrete type in generic method

I have a method that returns a List of objects that implement an interface:
private List<IFoo> GetData(string key)
{
...returns a different concrete implementation depending on the key
switch (key)
{
case "Bar":
return new List<Bar>();//Bar:IFoo
break;
case "Foo":
return new List<Foo>();//Foo:IFoo
break;
case "FooBar":
return new List<FooBar>();//FooBar:IFoo
break;
//etc etc - (quite a lot of these)
}
}
And I want to convert the result to a DataTable:
var result = GetData("foobar");
return ConvertToDataTable(result)
and my implementation of ConvertToDataTable looks something like this:
private DataTable ConvertToDataTable<T>(IEnumerable<T> data)
{
//problem is typeof(T) is always IFoo - not FooBar
PropertyInfo[] properties = typeof(T).GetProperties();
DataTable table = new DataTable();
foreach (var prop in properties)
{
table.Columns.Add(prop.DisplayName, prop.PropertyType);
}
//etc..
}
How can I get the underlying type in the generic ConvertToDataTable method?
Replace typeof which is evaluated at compileTime by .GetType which is evaluated at runtime and you will get the coorect type, not the interface:
private DataTable ConvertToDataTable<T>(IEnumerable<T> data)
{
Type dataType;
if (data != null && data.Count() != 0)
{
//problem is typeof(T) is always IFoo - not FooBar
//typeof(T) will always return IFoo
//Will return the correct type
dataType = data.First().GetType();
}
else
{
return new DataTable();
//or throw ?
}
PropertyInfo[] properties = dataType.GetProperties();
DataTable table = new DataTable();
foreach (var prop in properties)
{
table.Columns.Add(prop.DisplayName, prop.PropertyType);
}
//etc..
}
GetType() is what gets you the concrete class at runtime. The answer you accepted is a good solution for the question you asked.
Now, from the point of view of what you're trying to accomplish, I wanted to offer that creating your DataTable doesn't really require that RTTI. Here's an implementation of your ConvertToDataTable method that "doesn't care" what T is, as long as it implements IFoo.
private static DataTable ConvertToDataTable<T>(IEnumerable<T> data)
{
// Reflect the properties from T which is IFoo
PropertyInfo[] properties = typeof(T).GetProperties();
DataTable table = new DataTable();
// Add columns
foreach (var prop in properties)
{
table.Columns.Add(
prop.Name,
prop.PropertyType
).DataType = prop.PropertyType;
}
Console.WriteLine("Inside the generic method: ");
// Add rows
foreach (var item in data)
{
// RE: For "the question you asked": Use GetType() for object info.
Console.WriteLine("...the concrete Type is " + item.GetType().Name);
// I would ask, though, do you really need it for anything here?
// But for "the thing you're trying to accomplish" (making a DataTable)
// - This goes by the public properties declared in the interface IFoo.
// - It pulls properties GENERICALLY for ANY class that implements IFoo.
object[] values =
properties.Select(property => property.GetValue(item)).ToArray();
table.Rows.Add(values);
}
return table;
}
It picks up whatever is declared in the IFoo interface:
internal interface IFoo
{
int ID { get; }
string Name { get; }
string Text { get; set; }
}
It works to pass in IEnumerable containing completely different classes because they both implement IFoo:
class FooA : IFoo
{
public int ID { get; } = 1;
public string Name { get; } = "I am Foo A";
public string Text { get; set; }
}
class FooB : IFoo
{
public int ID { get; } = 2;
public string Name { get; } = "I am Foo B";
public string Text { get; set; }
}
Console Output:
Inside the generic method:
...the concrete Type is FooA
...the concrete Type is FooB
D I S P L A Y P O P U L A T E D T A B L E
ID Name Text
1 I am Foo A
2 I am Foo B
You can download from our GitHub if you want to try it out.
using System;
using System.Collections.Generic;
using System.Data;
namespace StackOverflow001
{
class Program
{
static void Main(string[] args)
{
var data = GetData("Foo");
var table = ConvertToDataTable(data);
data = GetData("Bar");
table = ConvertToDataTable(data);
data = GetData("FooBar");
table = ConvertToDataTable(data);
}
static IEnumerable<FooBase> GetData(string key) =>
key switch
{
"Foo" => new List<Foo>(),
"Bar" => new List<Bar>(),
"FooBar" => new List<FooBar>(),
_ => throw new ArgumentException(nameof(key)),
};
static DataTable ConvertToDataTable(IEnumerable<FooBase> data)
{
var properties = data switch
{
List<Foo> _ => typeof(Foo).GetProperties(),
List<Bar> _ => typeof(Bar).GetProperties(),
List<FooBar> _ => typeof(FooBar).GetProperties(),
_ => throw new ArgumentException(nameof(data)),
};
DataTable table = new DataTable();
foreach (var prop in properties)
{
table.Columns.Add(prop.Name, prop.PropertyType);
}
return table;
}
}
interface IFoo {}
abstract class FooBase : IFoo { }
class Foo : FooBase { public int FooProp { get; set; } }
class Bar : FooBase { public int BarProp { get; set; } }
class FooBar : FooBase { public int FooBarProp { get; set; }}
}
I think that using interface and generic methods is a bad idea in this situation. Using inheritance can make your code much easier and cleaner.

How do write a generic function that takes a datarow and fill an object's properties?

I have some function like
private static UserInfo FillUserInfoFromDataRow(DataRow dr)
{
UserInfo user = new UserInfo();
user.UserID = (int) dr["UserID"];
user.UserName = (int) dr["UserName"];
user.ProjectID = (int) dr["ProjectID"];
user.ClassID = (int) dr["ClassID"];
..............
return user;
}
I'd like to write some generic function like
private static T FillEntityInfoFromDataRow(DataRow dr), that will treat analogous types ProjectInfo, JobInfo, etc.
I can get all columns names of the DataRow parameter, but I don't know how to get all the appropriate fields of the generic T type and how to do appropriate casting.
Is it some way to do this job?
Thanks!
Ilan.
Its better to make use of reflection there are no of example avaible on google to do this this.
Check the below example
namespace MyNamespace.Data
{
class Converter
{
public static void Fill(object LogicObject, DataRow Row)
{
Dictionary<string, PropertyInfo> props = new Dictionary<string,PropertyInfo>();
foreach (PropertyInfo p in LogicObject.GetType().GetProperties())
props.Add(p.Name, p);
foreach (DataColumn col in Row.Table.Columns)
{
string name = col.ColumnName;
if (Row[name] != DBNull.Value && props.ContainsKey(name))
{
object item = Row[name];
PropertyInfo p = props[name];
if (p.PropertyType != col.DataType)
item = Convert.ChangeType(item, p.PropertyType);
p.SetValue(LogicObject, item, null);
}
}
}
}
}
Check the full blog post : http://kasey-jo.blogspot.com/2009/04/using-reflection-to-fill-business-layer.html
I use this, which is sort of like what you need:
EDITED thanks to Heinzi
public virtual void LoadDataRow(DataRow drow, params string[] parameters)
{
this.LoadDataRow(drow);
foreach (string property in parameters)
{
try
{
if (drow[property] != null)
{
PropertyInfo pi = this.GetType().GetProperty(property);
if (pi != null && drow.Table.Columns.Contains(property))
{
pi.SetValue(this, drow[property], null);
}
}
}
catch { throw; }
}
}
In your case though, you might want to loop through th eproperty collection of your object first, and try to load from your dataset, but th eabove code should get you started.
EDIT
Found this on MSDN:
System.Reflection.PropertyInfo[] p = MyObject.GetType.GetProperties();
foreach(System.Reflection.PropertyInfo prop in p)
{
....
}
Delegate this functionality to each specific class itself by declaring abstarct method in base class.
BTW, I suggest to name this method like CreateFromDataRow()
abstract class InfoBase
{
public abstract InfoBase CreateFromDataRow(DataRow dr);
}
OR
abstract class InfoBase<T>
{
public abstract T CreateFromDataRow(DataRow dr);
}

How do I get around this lambda expression outer variable issue?

I'm playing with PropertyDescriptor and ICustomTypeDescriptor (still) trying to bind a WPF DataGrid to an object, for which the data is stored in a Dictionary.
Since if you pass WPF DataGrid a list of Dictionary objects it will auto generate columns based on the public properties of a dictionary (Comparer, Count, Keys and Values) my Person subclasses Dictionary and implements ICustomTypeDescriptor.
ICustomTypeDescriptor defines a GetProperties method which returns a PropertyDescriptorCollection.
PropertyDescriptor is abstract so you have to subclass it, I figured I'd have a constructor that took Func and an Action parameters that delegate the getting and setting of the values in the dictionary.
I then create a PersonPropertyDescriptor for each Key in the dictionary like this:
foreach (string s in this.Keys)
{
var descriptor = new PersonPropertyDescriptor(
s,
new Func<object>(() => { return this[s]; }),
new Action<object>(o => { this[s] = o; }));
propList.Add(descriptor);
}
The problem is that each property get's its own Func and Action but they all share the outer variable s so although the DataGrid autogenerates columns for "ID","FirstName","LastName", "Age", "Gender" they all get and set against "Gender" which is the final resting value of s in the foreach loop.
How can I ensure that each delegate uses the desired dictionary Key, i.e. the value of s at the time the Func/Action is instantiated?
Much obliged.
Here's the rest of my idea, I'm just experimenting here these are not 'real' classes...
// DataGrid binds to a People instance
public class People : List<Person>
{
public People()
{
this.Add(new Person());
}
}
public class Person : Dictionary<string, object>, ICustomTypeDescriptor
{
private static PropertyDescriptorCollection descriptors;
public Person()
{
this["ID"] = "201203";
this["FirstName"] = "Bud";
this["LastName"] = "Tree";
this["Age"] = 99;
this["Gender"] = "M";
}
//... other ICustomTypeDescriptor members...
public PropertyDescriptorCollection GetProperties()
{
if (descriptors == null)
{
var propList = new List<PropertyDescriptor>();
foreach (string s in this.Keys)
{
var descriptor = new PersonPropertyDescriptor(
s,
new Func<object>(() => { return this[s]; }),
new Action<object>(o => { this[s] = o; }));
propList.Add(descriptor);
}
descriptors = new PropertyDescriptorCollection(propList.ToArray());
}
return descriptors;
}
//... other other ICustomTypeDescriptor members...
}
public class PersonPropertyDescriptor : PropertyDescriptor
{
private Func<object> getFunc;
private Action<object> setAction;
public PersonPropertyDescriptor(string name, Func<object> getFunc, Action<object> setAction)
: base(name, null)
{
this.getFunc = getFunc;
this.setAction = setAction;
}
// other ... PropertyDescriptor members...
public override object GetValue(object component)
{
return getFunc();
}
public override void SetValue(object component, object value)
{
setAction(value);
}
}
Simply:
foreach (string s in this.Keys)
{
string copy = s;
var descriptor = new PersonPropertyDescriptor(
copy,
new Func<object>(() => { return this[copy]; }),
new Action<object>(o => { this[copy] = o; }));
propList.Add(descriptor);
}
With captured variables, it is where it is declared that is important. So by declaring the captured variable inside the loop, you get a different instance of the capture-class per iteration (the loop variable, s, is technically declared outside the loop).
Marc's solution is of course correct, but I thought I'd expand upon WHY below. As most of us know, if you declare a variable in a for or foreach statement, it only lives as long as what's inside, which makes it seem like the variable is the same as a variable declared in the statement-block of such a statement, but that's not right.
To understand it better, take the following for-loop. Then I'll re-state the "equivalent" loop in a while-form.
for(int i = 0; i < list.Length; i++)
{
string val;
list[i] = list[i]++;
val = list[i].ToString();
Console.WriteLine(val);
}
This works out to in while-form like below: (it isn't exactly the same, because continue will act differently, but for scoping rules, it's the same)
{
int i = 0;
while(i < list.Length)
{
{
string val;
list[i] = list[i]++;
val = list[i].ToString();
Console.WriteLine(val);
}
i++;
}
}
When "exploded" out this way, the scope of the variables becomes clearer, and you can see why it always captures the same "s" value in your program, and why Marc's solution shows where to place your variable so that a unique one is captured every time.
create a local copy of s inside your for loop and use that.
for(string s in this.Keys) {
string key = s;
//...
}
For some additional thoughts on this issue see
http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/

Looking for a syntactic shortcut for accessing dictionaries

I have an abstract base class that holds a Dictionary. I'd like inherited classes to be able to access the dictionary fields using a convenient syntax. Currently I have lots of code like this:
string temp;
int val;
if (this.Fields.TryGetValue("Key", out temp)) {
if (int.TryParse(temp, out val)) {
// do something with val...
}
}
Obviously I can wrap this in utility functions but I'd like to have a cool, convenient syntax for accessing the dictionary fields where I can simply say something like:
int result = #Key;
Is there any way to do something like this in C# (3.5)?
You could add an indexer to your class and pass the indexer's parameter through to the dictionary.
class Foo
{
// Initialized elsewhere
Dictionary<String,String> Fields;
public Int32 this[String key]
{
String temp = null;
Int32 val = 0;
if (this.Fields.TryGetValue(key, out temp)) {
Int32.TryParse(temp, out val);
}
return val;
}
}
Then given an instance of Foo called foo you could do this:
Int32 value = foo["Key"];
How about an extension method?
public static int TryGetInt(this IDictionary dict, string key)
{
int val;
if (dict.Contains(key))
{
if (int.TryParse((string)dict[key], out val))
return val;
else
throw new Exception("Value is not a valid integer.");
}
throw new Exception("Key not found.");
}
The closer you can get to a nice syntax is using extension methods:
public static class MyDictExtensionMethods
{
public static T Get<T>(this Dictionary<string, object> dict, string key)
where T: IConvertible
{
object tmp;
if (!dict.TryGetValue(key, out tmp))
return default(T);
try {
return (T) Convert.ChangeType(tmp, typeof(T));
} catch (Exception) {
return default(T);
}
}
}
Usage:
int val = this.Fields.Get<int>("Key");
You can then create additional overloads for specific types (i.e.: types that does not implement IConvertible and need specific conversion).
Assuming that it's not always an int you want (if it is, then why isn't it a Dictionary<string, int>?) - I think something like this works and gets pretty close:
int i = #int["Key"];
string s = #string["Key"];
object o = #object["Key"];
This combines the fact that identifiers can be prefixed with # (it's usually optional, but it's required if your identifier is a reserved keyword, like int or string) with the default indexed parameter from Andrew Hare's answer.
It does require another class to be used to get the indexing - though if you wanted to use parens instead of square brackets for the key name, you could use methods instead:
int i = #value<int>("Key");
Implementation would be something like:
class DerivedClass : BaseClass {
void Main() {
int i = #int["Key"];
}
}
abstract class BaseClass {
private Dictionary<string, string> D { get; set; }
protected Indexer<int> #int = new Indexer<int>(s => int.Parse(s), this);
protected Indexer<string> #string = new Indexer<string>(s => s, this);
protected Indexer<object> #object = new Indexer<object>(s => (object)s, this);
protected class Indexer<T> {
public T this[string key] {
get { return this.Convert(this.BaseClass.D[key]); }
}
private T Convert(string value) { get; set; }
private BaseClass { get; set; }
public Indexer(Func<T, string> c, BaseClass b) {
this.Convert = c;
this.BaseClass = b;
}
}
}
Or, the method route:
class DerivedClass : BaseClass {
void Main() {
int i = #value<int>("key");
}
}
abstract class BaseClass {
private Dictionary<string, string> D { get; set; }
protected T #value<T>(string key) {
string s = this.D[s];
return Convert.ChangeType(s, typeof(T));
}
}
After reading through the language spec - if you're not tied to #, _ is a legal identifier. Combine that with indexers and you get:
int i = _["key"];

Convert DataTable to List<T>

I have a doubt, sometime I made this conversion from DataTable to List<T>:
List<EDog> lstDogs = (from drRow in dsDogs.Tables[0].AsEnumerable()
select new EDog()
{
intIdDog = drRow.Field<int>("IdDog"),
intIdOwner = drRow.Field<int?>("IdOwner"),
intAge = drRow.Field<int>("Age"),
strName = drRow.Field<string>("Name")
}).ToList();
This worked fine, but now I'm thinking about doing it generic, so that any type of DataSet could be converted to a strongly typed list.
How could I make it generic? maybe a delegate surrounding this part and creating the object?
new EDog()
{
intIdDog = drRow.Field<int>("IdDog"),
intIdOwner = drRow.Field<int?>("IdOwner"),
intAge = drRow.Field<int>("Age"),
strName = drRow.Field<string>("Name")
}
I tried it but get an error:
select (lambda) expected....
Any suggestion?
The reason why I need this is because each DataRow of the result, needs to be converted to an Entity for better manipulation.
Ok, let's have some fun:
public static class DataTableExtensions
{
public static List<T> ToGenericList<T>(this DataTable datatable, Func<DataRow, T> converter)
{
return (from row in datatable.AsEnumerable()
select converter(row)).ToList();
}
}
class EDog
{
private int intIdDog;
private int intIdOwner;
private int intAge;
private string strName;
...
public static EDog Converter(DataRow row)
{
return new EDog
{
intIdDog = (int)row["IdDog"],
intIdOwner = (int)row["IdOwner"],
intAge = (int)row["Age"],
strName = row["Name"] as string
};
}
}
Usage:
List<EDog> dogs = dsDogs.Tables[0].ToGenericList<EDog>(EDog.Converter);
But there is not enough fun, right? What about this:
class DataRowKeyAttribute : Attribute
{
private readonly string _Key;
public string Key
{
get { return _Key; }
}
public DataRowKeyAttribute(string key)
{
_Key = key;
}
}
static class DataTableExtensions
{
public static List<T> ToGenericList<T>(this DataTable datatable) where T : new()
{
return (from row in datatable.AsEnumerable()
select Convert<T>(row)).ToList();
}
private static T Convert<T>(DataRow row) where T : new()
{
var result = new T();
var type = result.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
var dataRowKeyAttribute = fieldInfo.GetCustomAttributes(typeof (DataRowKeyAttribute), true).FirstOrDefault() as DataRowKeyAttribute;
if (dataRowKeyAttribute != null)
{
fieldInfo.SetValue(result, row[dataRowKeyAttribute.Key]);
}
}
return result;
}
}
class EDog
{
[DataRowKey("IdDog")]
private int intIdDog;
[DataRowKey("IdOwner")]
private int intIdOwner;
[DataRowKey("Age")]
private int intAge;
[DataRowKey("Name")]
private string strName;
...
}
Usage:
List<EDog> dogs = dsDogs.Tables[0].ToGenericList<EDog>();
And if you want to have REAL fun, add error handling, consider caching reflection data to improve performance and changing fields to properties.
Is something like this what you are looking for?
public static List<T> ConvertDS<T>(DataSet ds, Converter<DataRow, T> converter)
{
return
(from row in ds.Tables[0].AsEnumerable()
select converter(row)).ToList();
}
It won't lend itself to easily be converted, you can do it but it probably won't save much work.
Think about the intrinsic knowledge in your code sample: you know the type and name of each column in the DataTable and the type and name of the property it maps to in the output type. The alternative would be to know the type and index of each column (substituting name for index). In both cases you would need to define a mapping to contain that information.
The alternative would be to build a convention-based convertor--in other words your DataTable column names and their target properties would need to be named consistently and deviating from that convention would result in the conversion failing.
I was able to do it in one line of code:
dt is the DataTable
List<DataRow> alist = new dt.AsEnumerable().ToList();

Categories

Resources