I have currently been learning and researching Generic's inside C# but am struggling with actually using the method once created.
I have tried:
public class myTestClass
{
class example
{
public static DataTable LINQtoDataTable<T>(IEnumerable<T> data)
{
DataTable dt = new DataTable();
PropertyInfo[] objectProps = null; // Reflection
if (data == null) return null;
foreach (T record in data)
{
if (objectProps == null) objectProps = ((Type)data.GetType()).GetProperties();
foreach (PropertyInfo pi in objectProps)
{
Type columnType = pi.PropertyType;
if ((columnType.IsGenericType) && (columnType.GetGenericTypeDefinition() == typeof(Nullable<>))) columnType = columnType.GetGenericArguments()[0];
dt.Columns.Add(new DataColumn(pi.Name, columnType));
}
}
return dt;
}
}
example ex { get; set; }
public myTestClass()
{
this.ex = new example();
}
}
But when I do (In a C# Form):
// Namespace area
myTestClass test;
// Main Method
test = new myTestClass();
test.LINQtoDataTable() doesn't come up or exist. Can anyone please help me out? I am confused to why this won't appear since I public'd the method and instanced the class it is inside :(
Greatly appreciated & thanks in advance.
You are trying to create extension method, and for extension method there are some pre-requisites for the method to have, it should be static and in a static class, the one you are missing is this keyword and your class is not static in start of it:
public static DataTable LINQtoDataTable<T>(this IEnumerable<T> data)
{
DataTable dt = new DataTable();
PropertyInfo[] objectProps = null; // Reflection
if (data == null) return null;
foreach (T record in data)
{
if (objectProps == null) objectProps = ((Type)data.GetType()).GetProperties();
foreach (PropertyInfo pi in objectProps)
{
Type columnType = pi.PropertyType;
if ((columnType.IsGenericType) && (columnType.GetGenericTypeDefinition() == typeof(Nullable<>))) columnType = columnType.GetGenericArguments()[0];
dt.Columns.Add(new DataColumn(pi.Name, columnType));
}
}
return dt;
}
and you will still now see it in intellisense, because you are creating extension method for IEnumerable<T> while you are trying to call it on just T.
For able to call it, you have to create a List<T> :
List<myTestClass> listTestClass = new List<myTestClass>();
listTestClass.Add(new myTestClass());
listTestClass.LINQtoDataTable();
I once wrote a blog post on extension methods topic, you may want to read about extension method with a simple examplehere
An extension-method exists in a static public class whilst your current code has only a static method within a private class. So you need this:
public static class MyTestClass {
public static DataTable LINQtoDataTable<T>(this IEnumerable<T> data) { ... }
}
Furthermore you need the this-keyword on the param you want to be that extension-method be bound to.
Last an extension-method can´t stay in a nested class, which you apparently don´t really need at all. Delete the nested class and make MyTestClass (also consider the naming-conventions for classes) publc and static and put the method there. Thus you won´t need any instance of this class. Simpy call myEnumerable.LINQtoDataTable().
becuse the LINQtoDataTable metode it static, is not need an example instance. which locat in the ex propery, and accessible via its name.
myTestClass.example.LINQtoDataTable(...)
Related
Hy, this is my first question here! I'm really struggling with these code bellow:
I have these class:
public class Home {
public List<Parameter> Parameter { get; set; }
}
I also have a function with this specs:
public static List<T> DataTableMapToList<T>(DataTable dtb)
{ ... }
In another class when I need call these function, I need pass the type of the my class but I'm in a reflection properties loop:
public void Initialize(ref object retObject)
{
using (var db = this)
{
db.Database.Initialize(force: false);
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandText = sStoredProcedure;
try
{
// Run the sproc
db.Database.Connection.Open();
DbDataReader reader = cmd.ExecuteReader();
DataSet ds = new DataSet();
ds.EnforceConstraints = false;
ds.Load(reader, LoadOption.OverwriteChanges, sTables);
var propertys = GetGenericListProperties(retObject);
foreach (DataTable table in ds.Tables) {
foreach (var info in propertys)
{
if (info.Name == table.TableName)
{
Type myObjectType = info.PropertyType;
// Create an instance of the list
var list = Activator.CreateInstance(myObjectType);
var list2 = DataTableMapToList<???>(table).ToList();
//Where the variable myObjectType is the TYPE of the class where I need to pass on the ??? marker
info.SetValue(retObject, list, null);
}
}
}
}
finally
{
db.Database.Connection.Close();
}
}
}
Where:
retObject -> An instance of Home;
info -> It's Home.Parametro property;
I wanna set - by reflection - the property dynamically. Everything is working without the call of the function with generic type. But I need call the function to populate the property correctly.
I've tried everything:
Pass as object and try convert after (I got an error of IConverter must be implemented);
Tried to put all my code - just for test - of the DataTableMapToList() and even so I got error of object conversion;
Force send list for my final variable but I have converter error again.;
I don´t know if I was clear enough about what I really need but I'm spend about 4 hours looking for a solution until know.
Given that there is a class with a static generic function:
public static class Utils
{
public static List<T> DataTableMapToList<T>(DataTable dtb)
{ ... }
}
It can be invoked using reflection:
IEnumerable InvokeDataTableMap(DataTable dtb, Type elementType)
{
var definition = typeof(Utils).GetMethod("DataTableMapToList");
var method = definition.MakeGenericMethod(elementType);
(IEnumerable) return method.Invoke(null, new object[]{dtb});
}
I need a function with following signature in C# 4.0, I am lost where to start :
public static object SetStringPropertiesOnly(object obj)
{
//iterate all properties of obj
//if the type of the property is string,
//return obj
}
and eventually I want to use this function for my several objects derived from different classes:
myClass1 obj1 = new myClass1 ();
myClass2 obj2 = new myClass2 ();
.....
.....
obj1 = SetStringPropertiesOnly(obj1);
obj2 = SetStringPropertiesOnly(obj2);
So the type of the objects are dynamic here.
Is such a method possible?.
Thanks.
public static object SetStringPropertiesOnly(object obj)
{
//Get a list of properties where the declaring type is string
var stringProps = obj.GetType().GetProperties().Where(x => x.PropertyType == typeof(string)).ToArray();
foreach (var stringProp in stringProps)
{
// If this property exposes a setter...
if (stringProp.SetMethod != null)
{
//Do what you need to do
stringProp.SetValue(obj, "value", null);
}
}
//What do you want to return?
return obj;
}
Consider changing your method signature to accept a value parameter and also change object obj to be ref, you don't need to return your object then.
I suppose you want to return the object itself.
However you should understand that the original object will also be changed.
public static object SetStringPropertiesOnly(object obj)
{
var properties = obj.GetType().GetProperties();
var strings = properties.Where(p=>p.PropertyType == typeof(string);
foreach(PropertyInfo property in strings)
{
property.SetValue(obj, "Value");
}
return obj;
}
My approach would be to make an extension method and return void, since the object would be changed. I also would add the wished string as a parameter.
public static void SetStringProperties(this object obj, string value)
{
var properties = obj.GetType().GetProperties();
var strings = properties.Where(p=>p.PropertyType == typeof(string);
foreach(PropertyInfo property in strings)
{
property.SetValue(obj, value);
}
return obj;
}
You can call the extension method like this:
obj.SetStringProperties("All strings will have this value");
By the way, the fact that you need to do this might be considered a "bad smelling code". Reconsider this design if you can.
Aint hard using reflection. And we can also do it as object extension (looks cute when you use it):
public static class ObjectExtensions
{
public static T SetStringPropertiesOnly<T>(this T obj) where T : class
{
var fields = obj.GetType().GetProperties();
foreach (var field in fields)
{
if (field.PropertyType == typeof (string))
{
field.SetValue(obj, "blablalba", null); //set value or do w/e your want
}
}
return obj;
}
}
and usage:
var obj = someObject.SetStringPropertiesOnly();
You could use a common interface, something in the lines of "IBulkStringEditable". The interface should contain a method "void SetStrings()".
Then all your classes have to implement this interface and the SetStrings method, where every class has different contents for SetStrings, depending on the string properties it has and the values you want them to have.
Then modify the SetStringPropertiesOnly function in this manner:
public static IBulkStringEditable SetStringPropertiesOnly(IBulkStringEditable obj)
{
obj.SetStrings();
return obj;
}
simply u can use dynamic in ur method parameter signature like that--->
public static object SetStringPropertiesOnly(dynamic obj)
{
// proceed
}
Two problems in one here ...
I have a set of DataRow wrappers (in VS2008) that inherit from a base class (called RecordBase). They all have a field called TableName. I wanted to make a generic enumerator that is an extension method to a DataSet. The specific TableName would select which table in the DataSet to enumerate. I'd like to write
public static IEnumerable<T> GetRecords<T>(this DataSet MySet) where T : RecordBase
{
foreach (DataRow row in MySet.Tables[T.TableName].Rows)
{
yield return new T(row);
}
}
Problem 1: I can’t find a way to have an overrideable static field, forcing me to create a dummy instance of the wrapper just to get the TableName.
Problem 2: Less serious, even though the wrappers (and the base) have a constructor that accepts a DataRow the compiler still insists that I use the parameterless constructor constraint.
All of which leaves me with code looking like
public static IEnumerable<T> GetRecords<T>(this DataSet MySet) where T : RecordBase, new()
{
string TableName = (new T()).TableName;
foreach (DataRow row in MySet.Tables[TableName].Rows)
{
T record = new T();
record.RowData = row;
yield return record;
}
}
Any ideas?
You can use an custom attribute for the table name and Activator to instantiate the type:
[Table("Customers")]
class Customer : RecordBase { }
//...
public static IEnumerable<T> GetRecords<T>(this DataSet MySet) where T : RecordBase
{
var attribT = typeof(TableAttribute);
var attrib = (TableAttribute) typeof(T).GetCustomAttributes(attribT,false)[0];
foreach (DataRow row in MySet.Tables[attrib.TableName].Rows)
{
yield return (T) Activator.CreateInstance(typeof(T),new[]{row});
}
}
Okay I'm looking for some input, I'm pretty sure this is not currently supported in .NET 3.5 but here goes.
I want to require a generic type passed into my class to have a constructor like this:
new(IDictionary<string,object>)
so the class would look like this
public MyClass<T> where T : new(IDictionary<string,object>)
{
T CreateObject(IDictionary<string,object> values)
{
return new T(values);
}
}
But the compiler doesn't support this, it doesn't really know what I'm asking.
Some of you might ask, why do you want to do this? Well I'm working on a pet project of an ORM so I get values from the DB and then create the object and load the values.
I thought it would be cleaner to allow the object just create itself with the values I give it. As far as I can tell I have two options:
1) Use reflection(which I'm trying to avoid) to grab the PropertyInfo[] array and then use that to load the values.
2) require T to support an interface like so:
public interface ILoadValues
{
void LoadValues(IDictionary values);
}
and then do this
public MyClass<T> where T:new(),ILoadValues
{
T CreateObject(IDictionary<string,object> values)
{
T obj = new T();
obj.LoadValues(values);
return obj;
}
}
The problem I have with the interface I guess is philosophical, I don't really want to expose a public method for people to load the values. Using the constructor the idea was that if I had an object like this
namespace DataSource.Data
{
public class User
{
protected internal User(IDictionary<string,object> values)
{
//Initialize
}
}
}
As long as the MyClass<T> was in the same assembly the constructor would be available. I personally think that the Type constraint in my opinion should ask (Do I have access to this constructor? I do, great!)
Anyways any input is welcome.
As stakx has said, you can't do this with a generic constraint. A workaround I've used in the past is to have the generic class constructor take a factory method that it can use to construct the T:
public class MyClass<T>
{
public delegate T Factory(IDictionary<string, object> values);
private readonly Factory _factory;
public MyClass(Factory factory)
{
_factory = factory;
}
public T CreateObject(IDictionary<string, object> values)
{
return _factory(values);
}
}
Used as follows:
MyClass<Bob> instance = new MyClass<Bob>(dict => new Bob(dict));
Bob bob = instance.CreateObject(someDictionary);
This gives you compile time type safety, at the expense of a slightly more convoluted construction pattern, and the possibility that someone could pass you a delegate which doesn't actually create a new object (which may or may not be a major issue depending on how strict you want the semantics of CreateObject to be).
If you can create common base class for all of T ojects that you are going to pass to MyClass as type parameters than you can do following:
internal interface ILoadValues
{
void LoadValues<TKey, TValue>(IDictionary<TKey, TValue> values);
}
public class Base : ILoadValues
{
void ILoadValues.LoadValues<TKey, TValue>(IDictionary<TKey, TValue> values)
{
// Load values.
}
}
public class MyClass<T>
where T : Base, new()
{
public T CreateObject(IDictionary<string,object> values)
{
ILoadValues obj = new T();
obj.LoadValues(values);
return (T)obj;
}
}
If you cannot have common base class than I think you should go with solution proposed by itowlson.
I'm legitimately curious at how you would load the values of a class without using reflection unless you had methods hardcoded to accomplish it. I'm sure there's another answer, but I'm not too ashamed to say I do not have experience in it. As for something I wrote to auto-load data, I have two base data classes I work from: a single object and then a list. In the single object (BaseDataClass), I have this method.
public virtual void InitializeClass(DataRow dr)
{
Type type = this.GetType();
PropertyInfo[] propInfos = type.GetProperties();
for (int i = 0; i < dr.ItemArray.GetLength(0); i++)
{
if (dr[i].GetType() != typeof(DBNull))
{
string field = dr.Table.Columns[i].ColumnName;
foreach (PropertyInfo propInfo in propInfos)
{
if (field.ToLower() == propInfo.Name.ToLower())
{
// get data value, set property, break
object o = dr[i];
propInfo.SetValue(this, o, null);
break;
}
}
}
}
}
And then in the data list
public abstract class GenericDataList<T> : List<T> where T : BaseDataClass
{
protected void InitializeList(string sql)
{
DataHandler dh = new DataHandler(); // my general database class
DataTable dt = dh.RetrieveData(sql);
if (dt != null)
{
this.InitializeList(dt);
dt.Dispose();
}
dt = null;
dh = null;
}
protected void InitializeList(DataTable dt)
{
if (dt != null)
{
Type type = typeof(T);
MethodInfo methodInfo = type.GetMethod("InitializeClass");
foreach (DataRow dr in dt.Rows)
{
T t = Activator.CreateInstance<T>();
if (methodInfo != null)
{
object[] paramArray = new object[1];
paramArray[0] = dr;
methodInfo.Invoke(t, paramArray);
}
this.Add(t);
}
}
}
}
I'm open to criticism, because no one has ever reviewed this code before. I am the sole programmer where I work, so I do not have others to bounce ideas off of. Thankfully, now I've come across this website!
Edit: You know what? Looking at it now, I don't see why I shouldn't just rewrite that last method as
protected void InitializeList(DataTable dt)
{
if (dt != null)
{
Type type = typeof(T);
foreach (DataRow dr in dt.Rows)
{
T t = Activator.CreateInstance<T>();
(t as BaseDataClass).InitializeClass(dr);
this.Add(t);
}
}
}
I assume that works, although I haven't tested it. No need to use reflection on that part.
I've created generic List and populate with some objects. Then List I mentioned before converted into DataTable to use in DataGridView. Problem is when I want get Row from this grid I have DataRow. I wanted to convert this to my object againt but not sure how to do it. Maybe you could give some example?
Thanks
Well, if you can't or won't use an "ORM" (object-relational mapper, like Linq-to-SQL or NHibernate - that's exactly what these tools do, and do quite well for you), you'll have to do this yourself.
Converting a DataRow into a domain object model is pretty boring code, really:
public Customer ConvertRowToCustomer(DataRow row)
{
Customer result = new Customer();
result.ID = row.Field<int>("ID");
result.Name = row.Field<string>("CustomerName");
..... // and so on
return result;
}
The biggest challenge here is making this rock-solid and handling (or avoiding) all possible errors (like a field being NULL etc.).
Another possibility would be to have a constructor on your domain model object type that would take a DataRow as parameter and construct a new object from it.
Marc
Assuming you're using a class MyObject, defined as follows :
class MyObject
{
public string Foo { get; set; }
public int Foo { get; set; }
}
You could do something like that :
using System.Data.DataSetExtensions;
...
List<MyObject> list = (from row in table.AsEnumerable()
select new MyObject
{
Foo = row.Field<string>("foo"),
Bar = row.Field<int>("bar")
}).ToList();
Why not just put your objects into a BindingList<> rather than a List<>? Then you can skip the converting to DataTable and back again exercise. You may need to implement INotifyPropertyChanged on your objects, but once they are inside a BindingList, changes in the datagrid will automatically be applied to your underlying objects.
Sorting can be handled by either sorting the list manually on column header click, or by inheriting from BindingList<> and implementing the sorting functionality inside it - then clicking on a header automatically sorts the list - no code required.
Well nowadays it is easier using ORMs of course. But if still you're using the old fashion you can go with a pretty easy Extension Class to do the job for you using a little bit of reflection and generic methods and lambda as follows:
public static class MapperExtensionClass
{
public static IEnumerable<MyClassType> ToMyClassTypeEnumerable(this DataTable table)
{
return table.AsEnumerable().Select(r => r.ToMyClassType());
}
public static MyClassType ToMyClassType(this DataRow row)
{
return row.ToObject<MyClassType>();
}
public static T ToObject<T>(this DataRow row) where T: new()
{
T obj = new T();
foreach (PropertyInfo property in typeof(T).GetProperties())
{
if (row.Table.Columns.Contains(property.Name))
{
property.SetValue(obj, property.PropertyType.ToDefault(row[property.Name]));
}
}
return obj;
}
public static object ToDefault(this Type type, object obj)
{
if (type == null)
throw new Exception("Customized exception message");
var method = typeof(MapperExtensionClass)
.GetMethod("ToDefaultGeneric", BindingFlags.Static | BindingFlags.Public);
var generic = method.MakeGenericMethod(type);
return generic.Invoke(null, new object[] { obj });
}
public static T ToDefaultGeneric<T>(object obj)
{
if (obj == null || obj == DBNull.Value)
{
return default(T);
}
else
{
return (T)obj;
}
}
}
You should also remember GridView objects can bind a lot of data source types. So it is your decision from a design point about what you should go with.