Creating my own component with DataSource and DataBind() - c#

I want to do my component that works similar to most of data controls (MS, Telerek, etc.):
myControl.DataSource = new List<myClass>();
mycontrol.NameField = "Name";
myControl.ValueField = "Value";
myControl.DataBind;
I have some test code:
class myClass
{
public String Name
{
get { return _name; }
}
...
}
class control
{
public void process(object o)
{
Type type = o.GetType();
System.Reflection.PropertyInfo info = type.GetProperty("Name");
object val = info.GetValue(o,null);
System.Console.WriteLine(val.ToString());
}
public void bind(IEnumerable<object> list)
{
foreach (object o in list)
{
process(o);
}
}
}
class Program
{
static void Main(string[] args)
{
control c = new control();
List<myClass> data = new List<myClass>();
data.Add(new myClass("1 name", "first name", 1.0f));
c.bind(data.Cast<object>());
}
}
Of course I want to get rid of c.bind(data.Cast<object>());. What type should I pass as argument to that function? I have tried to pass Object, but there is a problem with casting argument back into list(control should be very universal and I dont want to have any fixed data types).
Thanks in advance.

You can try a generic method:
public void bind<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
process(item);
}
}
One easy performance hint: consider caching the PropertyInfo instance instead of re-generating it in each call to process().

Related

How to use SetValue of an Indexed Property in Reflection?

I have a C# Converter method which convers generic lists with the use of reflection.
The problem occurs when I try to call the SetValue method of the Item's property, it throws the following inner exception (ArgumentOutOfRangeException):
Index was out of range. Must be
non-negative and less than the size of the collection. Parameter name:
index.
Here is my code:
internal class Program
{
private static void Main()
{
List<ClassA> classA = new List<ClassA>();
classA.Add(new ClassA { Data = "value1" });
classA.Add(new ClassA { Data = "value2" });
List<ClassB> classB = Converter<List<ClassA>, List<ClassB>>(classA);
}
public static TOut Converter<TIn, TOut>(TIn request)
{
var response = Activator.CreateInstance<TOut>();
PropertyInfo propertyA = typeof(TIn).GetProperty("Item");
PropertyInfo propertyB = typeof(TOut).GetProperty("Item");
int count = (int)typeof(TIn).GetProperty("Count").GetValue(request);
for (int i = 0; i < count; i++)
{
var value = propertyA.GetValue(request, new object[] { i });
var b = CreateBFromA(propertyB, propertyA, value);
propertyB.SetValue(response, b, new object[] { i });
}
return response;
}
private static object CreateBFromA(PropertyInfo propertyB, PropertyInfo propertyA, object value)
{
var b = Activator.CreateInstance(propertyB.PropertyType);
object o = propertyA.PropertyType.GetProperty("Data").GetValue(value);
propertyB.PropertyType.GetProperty("Data").SetValue(b, o);
return b;
}
}
internal class ClassA
{
public string Data { get; set; }
}
internal class ClassB
{
public string Data { get; set; }
public object Other { get; set; }
}
This is a small example code of a bigger generic method (where I need to use reflection), so you can try and run it to regenerate the exception.
How to use the SetValue method to avoid this exception?
Here is my aproach to it:
public static TCollectionOut ConvertCollection<TCollectionIn, TCollectionOut, TIn, TOut>(TCollectionIn input)
where TCollectionIn : IEnumerable<TIn>
where TCollectionOut : ICollection<TOut>, new()
where TOut : new()
{
var res = new TCollectionOut();
foreach (dynamic item in input)
{
dynamic o = new TOut();
ConvertItem(item, o);
res.Add(o);
}
return res;
}
public static TCollectionOut ConvertCollectionMoreDynamic<TCollectionIn, TCollectionOut>(TCollectionIn input)
where TCollectionIn : IEnumerable
{
dynamic res = Activator.CreateInstance(typeof (TCollectionOut));
var oType = typeof (TCollectionOut).GetMethod("Add").GetParameters().Last().ParameterType;
foreach (dynamic item in input)
{
dynamic o = Activator.CreateInstance(oType);
ConvertItem(item, o);
res.Add(o);
}
return res;
}
public static void ConvertItem(ClassA input, ClassB output)
{
output.Data = input.Data;
}
If you wich to support more types just create ConvertItem method with correct overload.
This is because you are trying to pass an index to a not indexed property (Data).
If you post the ClassA code I can try yo help. Anyway you can use LINQ to perform this kind of conversions. It's faster (to write and to execute) and type safe.

Get property of generic class

I have a generic class, and an object value where obj.GetType().GetGenericTypeDefinition() == typeof(Foo<>).
class Foo<T>
{
public List<T> Items { get; set; }
}
How do I get the value of Items from obj? Remember, obj is an Object, I can't cast obj as Foo because I don't know what T is.
I was hoping to use reflection for this, but each time I do GetProperty("Items") it returns null. However, if someone knows a good way to do this without reflection, by all means.
Let's say my code looks like this:
//just to demonstrate where this comes from
Foo<int> fooObject = new Foo<int>();
fooObject.Items = someList;
object obj = (object)fooObject;
//now trying to get the Item value back from obj
//assume I have no idea what <T> is
PropertyInfo propInfo = obj.GetType().GetProperty("Items"); //this returns null
object itemValue = propInfo.GetValue(obj, null); //and this breaks because it's null
You should be able to use:
Type t = obj.GetType();
PropertyInfo prop = t.GetProperty("Items");
object list = prop.GetValue(obj);
You will not be able to cast as a List<T> directly, of course, as you don't know the type T, but you should still be able to get the value of Items.
Edit:
The following is a complete example, to demonstrate this working:
// Define other methods and classes here
class Foo<T>
{
public List<T> Items { get; set; }
}
class Program
{
void Main()
{
//just to demonstrate where this comes from
Foo<int> fooObject = new Foo<int>();
fooObject.Items = new List<int> { 1, 2, 3};
object obj = (object)fooObject;
//now trying to get the Item value back from obj
//assume I have no idea what <T> is
PropertyInfo propInfo = obj.GetType().GetProperty("Items"); //this returns null
object itemValue = propInfo.GetValue(obj, null);
Console.WriteLine(itemValue);
// Does not print out NULL - prints out System.Collections.Generic.List`1[System.Int32]
IList values = (IList)itemValue;
foreach(var val in values)
Console.WriteLine(val); // Writes out values appropriately
}
}
#ReedCopsey is absolutely correct, but in case you're really asking the question "How do I fish out the generic details of a type?", here's some "Fun with Reflection":
public void WhatsaFoo(object obj)
{
var genericType = obj.GetType().GetGenericTypeDefinition();
if(genericType == typeof(Foo<>))
{
// Figure out what generic args were used to make this thing
var genArgs = obj.GetType().GetGenericArguments();
// fetch the actual typed variant of Foo
var typedVariant = genericType.MakeGenericType(genArgs);
// alternatively, we can say what the type of T is...
var typeofT = obj.GetType().GetGenericArguments().First();
// or fetch the list...
var itemsOf = typedVariant.GetProperty("Items").GetValue(obj, null);
}
}
Something like this should do the trick:
var foo = new Foo<int>();
foo.Items = new List<int>(new int[]{1,2,3});
// this check is probably not needed, but safety first :)
if (foo.GetType().GetProperties().Any(p => p.Name == "Items"))
{
var items = foo.GetType().GetProperty("Items").GetValue(foo, null);
}
You have to use System.Reflection namespace to execute the program successfully.
This program gives you Property Name and Value of any Generic Class
You can check this code fiddle on C# Online Rexter Tool Compiler at
using System;
using System.Reflection;
namespace GenericPropertyExample
{
//Declaring a Sample Class
public class class1
{
public string prop1 { get; set; }
public string prop2 { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
//Creating Class Object
class1 objClass1 = new class1 { prop1 = "value1", prop2 = "value2" };
//Passing Class Object to GenericPropertyFinder Class
GenericPropertyFinder<class1> objGenericPropertyFinder = new GenericPropertyFinder<class1>();
objGenericPropertyFinder.PrintTModelPropertyAndValue(objClass1);
Console.ReadLine();
}
//Declaring a Generic Handler Class which will actually give Property Name,Value for any given class.
public class GenericPropertyFinder<TModel> where TModel : class
{
public void PrintTModelPropertyAndValue(TModel tmodelObj)
{
//Getting Type of Generic Class Model
Type tModelType = tmodelObj.GetType();
//We will be defining a PropertyInfo Object which contains details about the class property
PropertyInfo[] arrayPropertyInfos = tModelType.GetProperties();
//Now we will loop in all properties one by one to get value
foreach (PropertyInfo property in arrayPropertyInfos)
{
Console.WriteLine("Name of Property is\t:\t" + property.Name);
Console.WriteLine("Value of Property is\t:\t" + property.GetValue(tmodelObj).ToString());
Console.WriteLine(Environment.NewLine);
}
}
}
}
}
Hey guys ive been struggeling with the same issue with generic typs and finally found the solution that gets the value
--------Small code snippet of the method that does the trick ------------------
public void printFields()
{
// Is the list empty
if (this.list_.Count == 0)
{
//Y => Forced exit no object info
return;
}
try
{
// Get first item from list
T item = this.list_[0];
// Get the type of object
//**Type thisType = item.GetType();
// Get array of all fields
FieldInfo[] thisFieldInfo = item.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
// Loop through all fields and show its info
for (int ix = 0; ix < thisFieldInfo.Length; ix++)
{
// Get Field value
String strVal = thisFieldInfo[ix].GetValue(item).ToString();
// Display item
Console.WriteLine("'{0}' is a {1} and has value {2}", thisFieldInfo[ix].Name, thisFieldInfo[ix].FieldType, strVal);
}
}
catch (SecurityException e)
{
Console.WriteLine("Exception: " + e.Message);
}
}

get dictionary value using .(dot) operator using dynamic keyword, it's possible?

I have the following class:
public class foo
{
public Dictionary<string, string> data = new Dictionary<string, string>();
public foo(params object[] args)
{
foreach (object arg in args)
{
data.Add(arg.ToString(), "..");
}
}
}
I need get the value of dictionary using the dot operadotor it's because the class that I set the class as arguments use the dynamic keyword to "walk" on the class.
for example:
var args = new[] {"a","b","c"};
var Foo = new foo(args);
var baa = Foo.data.a;
Console.Write(baa); // ..
if exists an way to make dynamic variables, something like:
public foo(params object[] args) {
foreach (object arg in args) {
var name = (string) arg;
var value = "..";
MakeVariable(name, value);
}
}
makes an variable named of arg and the value .. as public member of foo class.
anyway differents to solve this is very appreciated. Thanks in advance.
You can have Foo inherit from DynamicObject:
public class Foo : DynamicObject
{
private Dictionary<string, string> data = new Dictionary<string, string>();
public Foo(params object[] args)
{
foreach (object arg in args)
{
data.Add(arg.ToString(), "..");
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (data.ContainsKey(binder.Name))
{
result = data[binder.Name];
return true;
}
return base.TryGetMember(binder, out result);
}
}
To use it you can use dynamic to hold an instance of Foo:
var args= new[] { "a", "b", "c" };
dynamic foo = new Foo(args);
var myA = foo.a; //returns ".."
Keep in mind that you will lose type safety since you have to use dynamic - your use case should really justify this disadvantage - usually there is a better approach.
I think you should use DynamicObject. If you are using an older version of the framework the only option is Reflection.Emit
The dynamic works something like this
// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
Another option is to use the ExpandoObject class if you want to directly expose the Data member, as in your example. This keeps the code simpler if you don't need to define specific operations that would require inheriting DynamicObject.
public class Foo
{
public dynamic Data = new ExpandoObject();
public Foo(params object[] args)
{
var dataDict = (IDictionary<string, object>)Data;
foreach (var obj in args)
{
dataDict.Add(obj.ToString(), "..");
}
}
}
Usage:
var foo = new Foo("a", "b", "c");
Console.WriteLine(foo.Data.a);
((IDictionary<string, object>)foo.Data).Add("d", "!");
foreach (var item in foo.Data)
{
Console.WriteLine("{0} : {1}", item.Key, item.Value);
}
Notice that I cast to a dictionary and added "d" although I could've also assigned it directly: foo.Data.d = "!". The only difference is you may not know ahead of time what field names you have, and the former example allows you to setup the ExpandoObject based on dynamic input, whereas the latter is useful when you already know what field name to use.
In .NET 4 this exact behavior is implemented by ExpandoObject class:
public class Foo
{
private readonly ExpandoObject _dict = new ExpandoObject();
public dynamic Data
{
get { return _dict; }
}
public Foo(params object[] args)
{
foreach (var arg in args)
_dict.Add(arg.ToString(), "..");
}
}
var foo = new Foo("a", "b", "c");
foo.Data.x = 3.14;
Console.Write(foo.Data.a);

Casting to a collection with a dynamic type

How can I set generic type dynamically?
public class A
{
public int X { get; set; }
public A()
{
X = 9000;
}
}
public class Class1
{
public void Test()
{
List<A> theList = new List<A>() {
new A { X = 1 },
new A { X = 2 }
};
object testObj = theList;
var argType = testObj.GetType().GetGenericArguments()[0];
Foo(testObj as ICollection<argType>); // ?
}
public void Foo<T>(ICollection<T> items) where T:new()
{
T newItem = new T();
items.Add(newItem);
}
To do in "regular" c# you would use reflection to obtain the MethodInfo, then use MakeGenericMethod() and Invoke(). However, this is easier:
Foo((dynamic)testObj);
The reflection approach here is:
var method = typeof(Class1).GetMethod("Foo").MakeGenericMethod(argType);
method.Invoke(this, new object[] { testObj });
You can't do that, because in the Foo function you are supposed to do something with the collection, and there's no guarantee that the type will be safe.
The only way is using an "object" then casting to the proper type within the Fooo function.

C# getting details from subclasses

I'm a complete newbie to C# so excuse me if this looks weird.
I have an abstract class called vefHlutir
namespace Klasasafn
{
public abstract class vefHlutur
{
public abstract List<String> columnNames();
public abstract List<String> toStringList();
}
}
//Here is an object that inherits from this abstract class:
namespace Klasasafn
{
[Table(Name="Users")]
public class User: vefHlutur
{
public override List<String> columnNames()
{
List<String> p = new List<String>();
p.Add("Nafn");
p.Add("Email");
p.Add("Lýsing");
return p;
}
public override List<String> toStringList()
{
List<String> p = new List<String>();
p.Add(name);
p.Add(email);
p.Add(descr);
return p;
}
... more stuff here
}
}
//And here is the code I'm trying to run, Item, User and Category all inherit from vefHlutir:
List<Klasasafn.Item> hlutir;
List<Klasasafn.User> notendur;
List<Klasasafn.Category> flokkar;
void Page_Init(object sender, EventArgs e)
{
hlutir = Fac.getItemList();
notendur = Fac.getUserList();
flokkar = Fac.getCategoryList();
prenta(notendur, Table1);
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
if (DropDownList1.SelectedIndex == 0)
{
prenta(notendur, Table1);
}
else if (DropDownList1.SelectedIndex == 1)
{
prenta(hlutir, Table1);
}
else
prenta(flokkar, Table1);
}
private void prenta(List<vefHlutur> foo, Table f)
{
List<String> columnNames = foo[0].columnNames();
TableRow tRow1 = new TableRow();
f.Rows.Add(tRow1);
foreach (String i in columnNames)
{
TableCell columnNameCell = new TableCell();
tRow1.Cells.Add(columnNameCell);
columnNameCell.Controls.Add(new LiteralControl(i));
}
foreach (vefHlutur j in foo)
{
TableRow tRow = new TableRow();
f.Rows.Add(tRow);
List<String> töfluHlutir = j.toStringList();
foreach (String k in töfluHlutir)
{
TableCell tCell1 = new TableCell();
tRow.Cells.Add(tCell1);
tCell1.Controls.Add(new LiteralControl(k));
}
}
}
My problem is that I can't use the method prenta.
I always get these errors:
Error 1 The best overloaded method match for 'Forsíða.prenta(System.Collections.Generic.List, System.Web.UI.WebControls.Table)' has some invalid arguments
Error 2 Argument '1': cannot convert from 'System.Collections.Generic.List' to 'System.Collections.Generic.List
How do I solve this?
The problem is that in C#, the type List<ChildClass> cannot be used when the method is typed for List<ParentClass>. This type of conversion is known as covariance and it will not be available in C# until 4.0 and then only on interfaces and events.
What you can do though is make the method generic and add a constraint.
private void prenta<T>(List<T> foo, Table f)
where T : vefHlutur
{
...
}
What this code is doing is saying that prenta will accept a List<T> as the first parameter for any case where T is or derivecs from the type vefHlutur. It also allows you to treat the type T as if it is the type vefHlutur with respect to calling methods, properties, etc ... This should allow your scenario to work.
There is a way to do the cast. A little unsafe code! Don't be afraid of this post. Its mostly test code to show that it works. All the work happens here:
static unsafe List<A> CastBasAIL(List<B> bIn) {
DynamicMethod dynamicMethod = new DynamicMethod("foo1", typeof(List<A>),
new[] { typeof(List<B>) }, typeof(void));
ILGenerator il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // copy first argument to stack
il.Emit(OpCodes.Ret); // return the item on the stack
CCastDelegate HopeThisWorks = (CCastDelegate)dynamicMethod.CreateDelegate(
typeof(CCastDelegate));
return HopeThisWorks(bIn);
}
This solution works as long as the thing you are trying to cast has the same instance field layout as the thing you are casting it to (inheritance situations work well). Note, there are some things that will give you type mismatch errors: i.e. if the List attempts to create a base type in a covariant situation. Just test after doing this.
I apologize to purists for this, but I am a recovering c/c++vb/aseembly programmer!
namespace Covariant {
class A {
public virtual string Name() { return "A"; }
}
class B : A {
public override string Name() { return "B"; }
}
delegate List<A> CCastDelegate(List<B> b); // be used in the cast
class Program {
static unsafe List<A> CastBasAIL(List<B> bIn) {
DynamicMethod dynamicMethod = new DynamicMethod("foo1", typeof(List<A>), new[] { typeof(List<B>) }, typeof(void));
ILGenerator il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // copy first argument to stack
il.Emit(OpCodes.Ret); // return the item on the stack
CCastDelegate HopeThisWorks = (CCastDelegate)dynamicMethod.CreateDelegate(typeof(CCastDelegate));
return HopeThisWorks(bIn);
}
static void Main(string[] args) {
// make a list<B>
List<B> b = new List<B>();
b.Add(new B());
b.Add(new B());
// set list<A> = the list b using the covariant work around
List<A> a = CastBasAIL(b);
// at this point the debugger is miffed with a, but code exectuing methods of a work just fine.
// It may be that the debugger simply checks that type of the generic argument matches the
// signature of the type, or it may be that something is really screwed up. Nothing ever crashes.
// prove the cast really worked
TestA(a);
return;
}
static void TestA(List<A> a) {
Console.WriteLine("Input type: {0}", typeof(List<A>).ToString());
Console.WriteLine("Passed in type: {0}\n", a.GetType().ToString());
// Prove that A is B
Console.WriteLine("Count = {0}", a.Count);
Console.WriteLine("Item.Name = {0}", a[0].Name());
// see if more complicated methods of List<A> still work
int i = a.FindIndex(delegate(A item) { return item.Name() == "A"; });
Console.WriteLine("Index of first A in List<A> = {0}", i);
i = a.FindIndex(delegate(A item) { return item.Name() == "B"; });
Console.WriteLine("Index of first B in List<A> = {0}\n", i);
// can we convert a to an array still?
Console.WriteLine("Iterate through a, after converting a to an array");
foreach (var x in a.ToArray())
Console.WriteLine("{0}", x.Name());
}
}
}

Categories