I'm writing a wrapper for the WinForms ComboBox control that will let me populate the dropdown with a List<T>, and has a Selected property that returns an item of type T (or null if nothing selected).
Rather than having a Selected property, I'd like it to be named based on the generic type automatically. For example:
MyDropDownList<User> would have a SelectedUser property
MyDropDownList<Department> would have a SelectedDepartment property
MyDropDownList<State> would have a SelectedState property
With LINQ, I can create anonymous types during grouping, like so:
var usersByGender = users
.GroupBy(x => x.Gender)
.Select(group => new {Gender = group.Key, List = group.ToList()});
Which will result in a list of the generated anonymous type containing a Gender property and List<User> that are detectable by IntelliSense. The question is, can I somehow do this with properties in a generic class?
EDIT: I now realize I'm essentially asking for "method_missing" in C# 3.0, which is probably impossible. I'm open to suggestions, though.
I don't think you can do it. The only approach that has even a remote chance of working would be to create some kind of factory method that created the type and returned it. Basically your generic type becomes a base class and IL is dynamically written creating a concrete class that inherits from the generic but with the new property added in. Of course the object that is returned would be really anonymous and you'd only be able to access it through reflection since you wouldn't have a type to actually cast to:
public static class CrazyFactory
{
public static object CreateTypedComboList<T>()
{
//magic happens
return object;
}
}
Using it would then require
object userCombo = CrazyFactory.CreateTypedComboList<User>();
PropertyInfo selectedUserProperty = userCombo.GetType().GetProperty("SelectedUser");
selectedUserProperty.SetValue(userCombo, user);
Which is hardly a step up from a simple T SelectedItem property.
From a brief look it appears that this type of thing will be easier when c# 4.0 brings us dynamic types. By implementing the IDynamicObject interface it will be possible to catch all calls to undefined properties and handle them so you could use logic like the following:
public override MetaObject GetMember(GetMemberAction action, MetaObject[] args)
{
//not sure on the real property name here...
string actionName = action.Name;
if (actionName = "Selected" + typeof(T).Name)
{
return SelectedItem; //in some MetaObject wrapper
}
}
I've been following this article and haven't touched dynamics myself yet, but it certainly appears like what you want is possible. I still wouldn't do it though - you won't get Intellisense and it seems like a fragile and complicated method for defining functionality.
No, you cannot do that. The whole idea behind generic types is that they apply equally to all types which can be specified in the generic parameter. This wouldn't be the case if every specialization were allowed to declare differently-named members.
Related
The following code I saw in one of StackOverflow sites. But it is not explained in detail and I am unable to understand. Would anyone explain this?
public class MyArray<T>
{
T[] array = new T[10];
public T GetItem(int index)
{
return array[index];
}
}
I would like to know if this is a class.
How to instantiate this class?
How can I use the T array in the class?
Whether the array need to be created outside or inside in the class?
Generic classes <T> have type parameters. Separate classes, each with a different field type in them, can be replaced with a single generic class. The generic class introduces a type parameter. This becomes part of the class definition itself. It allows you to define type-safe data structures, without committing to actual data types. The most common use of generics is to create collection classes. This results in a significant performance boost and higher quality code, because you get to reuse data processing algorithms without duplicating type-specific code.
The letter T denotes a type that is only known based on the calling location. The program can act upon the instance of T like it is a real type, but it is not.
I would like to know if this is a class.
Yes it is a class
How to instantiate this class?
MyArray<int> = new MyArray<int>();
or
MyArray<string> = new MyArray<string>();
Or anyother type you like
How can I use the T array in the class?
Since we know that one of the common use of generics is to create collection classes. So you can also use it that way.
Whether the array need to be created outside or inside in the class?
Question is little vague bcoz which class you are talking about the declaring class or the implementation class. But assuming that you are talking about the class where you implement or create the object of Class. It should be inside the class like normal object initiator.
1: Yes, it's a class; hence the use of the class keyword.
2: var myArray = new MyArray<Something>(); where Something could be any type (with maybe the odd exception).
3: From within the class, just refer to array. You won't be able to do a lot with the items themselves, though, since you don't know what type they are.
4: The code you posted creates the array inside the class. The array is hidden, and the only access to it is through the GetItem method. What you posted must be incomplete, though, since that would not be useful and would not work. You need to be able to do more than try to get an item.
I would like to know if this is a class.
Yes this is a class and are called as Generic Classes, A Generic
classes encapsulate operations that are not specific to a particular
data type. The most common use for generic classes is with collections
like linked lists, hash tables, stacks, queues, trees, and so on.
Operations such as adding and removing items from the collection are
performed in basically the same way regardless of the type of data
being stored.
How to instantiate this class?
MyArray<int> myArrayInstance= new MyArray<int>();
How can I use the T array in the class?
You can use the name of the variable array to use them inside the class. and use the reference to access it from outside the class.
Whether the array need to be created outside or inside in the class
You can populate the array inside the class or it can be populated from the MyArray Constructor. like the following:
public MyArray(T[] inputArrayElements)
{
array = inputArrayElements;
}
Additional note, How to use GetItem
You can use myArrayInstance, the instance of the class to call the method. the calling will be like the following:
int itemAtIndexs = myArrayInstance.GetItem<int>(5);
// which will give you the item # 5th index
This is a generic class. This means that <T> will be a type when it's instantiated. For example, based on your code example, you would instantiate it as:
MyArray<int> integerArray = new MyArray<int>();
This would instantiate a strongly typed array of integers. It does this by passing T throughout the class. The same class could be used to store strings by doing the following.
MyArray<string> stringArray = new MyArray<string>();
The reason for this is to allow container classes to be more flexible in terms of what types they can contain. This makes them more reusable. Before generics, if you wanted a dynamic list, you needed to use an ArrayList which cast everything to type Object and then required you to manually upcast it back to the type it was meant to be.
There are plenty of built in generic classes such as List<T>, Dictionary<TKey, TValue>, etc. They can be found in the System.Generics module.
I am preferring to post an answer based on what others guided me with the hope that it will be helpful people like me who are in the lower rung of C# and learning something new.
namespace GenericArray
{
public class MyArray<T>
{
T[] array = new T[5];
public MyArray(int size)
{ //Not used in this programme, because the no. of elements is already set above.
}
public void SetItem(int index, T value)
{
array[0] = value;
}
public T GetItem(int index)
{
return array[index];
}
}
}
In the button event, I code like this.
private void button4_Click(object sender, EventArgs e)
{
MyArray<int> myInt = new MyArray<int>(5); //Initializing the generic class.
myInt.SetItem(0, 1); //array element 0 is going to be assigned a value of 1.
MessageBox.Show(myInt.GetItem(0).ToString());
//You can also use the same class, to set string values.
}
I have a UserControl which is designed to edit a collection of some arbitrary POCO. The POCO is selected at design time, so I can pass a description of the properties within the POCO that need to be displayed and edited but I'm struggling to see the best way to instantiate new POCOs within the control to add to the collection.
At the moment, I'm running with adding a new property to the control that holds an IPocoFactory but this doesn't seem satisfactory for a couple of reasons:
The control user has to do quite a bit of leg work creating a class that implements the IPocoFactory interface just to use the control which would otherwise be quite straightforward
Controls such as the DataGrid have already solved this problem (although I cannot seem to figure out how, despite poking around for a while with ILSpy!)
Can anyone suggest a decent pattern for this problem? I can't be the only one who's faced it!
It occurs to me that reflection might play a part in a solution, but I'm not quite sure about that either: I could examine the ItemsSource (a non-generic IEnumerable) to see what's in it, but if it's empty, there's nothing to look at.
You can get the type to be created by calling ItemsSource.GetType().GetInterfaces(), finding the Type object for the IEnumerable<T> interface (which any generic collection will implement), and calling GetGenericArguments() on it. IEnumerable<T> has one type argument, of course, so that's the type you need to create an instance of.
Then you can create an instance fairly easily (see UPDATE below for a static method which wraps this all up into a single method call):
ObjectType instance = (ObjectType)Activator.CreateInstance("AssemblyName",
"MyNamespace.ObjectType");
You'll need the assembly in which the type is declared, but that's a property of Type. Assembly has a CreateInstance method as well. Here's another way to do the same thing:
Type otype = typeof(ObjectType);
ObjectType instance = (ObjectType)otype.Assembly.CreateInstance(otype.FullName);
If the type to be instantiated doesn't have a default constructor, this gets uglier. You'd have to write explicit code to provide values, and there's no way to guarantee that they make any sense. But at least that's a much lighter burden to impose on the consumer than a mess of IPOCOFactory implementations.
Remember by the way that System.String doesn't have a default constructor. It's natural to test the code below with List<String>, but that's going to fail.
Once you have the type of the objects in ItemsSource, you can further simplify maintenance by programmatically enumerating the names and types of the properties and auto-generating columns. If desired, you could write an Attribute class to control which ones are displayed, provide display names, etc. etc.
UPDATE
Here's a rough implementation that's working for me to create instances of a class declared in a different assembly:
/// <summary>
/// Collection item type must have default constructor
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public static Object CreateInstanceOfCollectionItem(IEnumerable items)
{
try
{
var itemType = items.GetType()
.GetInterfaces()
.FirstOrDefault(t => t.Name == "IEnumerable`1")
?.GetGenericArguments()
.First();
// If it's not generic, we may be able to retrieve an item and get its type.
// System.Windows.Controls.DataGrid will auto-generate columns for items in
// a non-generic collection, based on the properties of the first object in
// the collection (I tried it).
if (itemType == null)
{
itemType = items.Cast<Object>().FirstOrDefault()?.GetType();
}
// If that failed, we can't do anything.
if (itemType == null)
{
return null;
}
return itemType.Assembly.CreateInstance(itemType.FullName);
}
catch (Exception ex)
{
return null;
}
}
public static TestCreate()
{
var e = Enumerable.Empty<Foo.Bar<Foo.Baz>>();
var result = CreateInstanceOfCollectionItem(e);
}
You could make CreateInstanceOfCollectionItem() an extension method on IEnumerable if you like:
var newItem = ItemsSource?.CreateInstanceOfCollectionItem();
NOTE
This depends on the actual collection being a generic collection, but it doesn't care about the type of your reference to the collection. ItemsControl.ItemsSource is of the type System.Collections.IEnumerable, because any standard generic collection supports that interface, and so can be cast to it. But calling GetType() on that non-generic interface reference will return the actual real runtime type of the object on the other end (so to speak) of the reference:
var ienumref = (new List<String>()) as System.Collections.IEnumerable;
// fullName will be "System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
// ...or something like it, for whatever version of .NET is on the host.
var fullName = ienumref.GetType().Name;
I have the class Columns which is derived from List<Column>. I want to populate the class inside one of its methods named GetColumns(). But I'm having trouble doing this. Maybe I'm missing something very very obvious here.
What I'm trying to do is to define Collections as classes that derive from `List and I want to extend these classes to populate them and other stuff.
public class Columns : List<Column>
{
public void GetColumns()
{`
this = Building.PColumns;
}
}
You can't assign to this in a class. (You could do so in a struct.)
Instead of:
this = Building.PColumns;
Try:
this.Clear();
this.AddRange(Building.PColumns);
If you're extending List you should just be able to call all the usual methods ie (add, addrange, remove etc..). Personally I would either extend IEnumerable or use Columns as a wrapper class with a member of type List but each to their own and it of course depends on what you're doing. Especially since you know the type of the list beforehand and you're handling the login in internal functions anyway, i would just have it as a member.
Change the body of the method GetColumns. It is a bit unclear where Building.PColumns is defined. In neither case the this pointer can be reassigned. Furthermore, the name GetColumns suggests that something is returned. However this is not the case as its return type is void. Change the return type of GetColumns to the type of Building.PColumns and return Building.PColumns.
is it possible to create a property on a type at runtime? My type "Account" has a predefined bunch of properties such has "ID" and "Account Name" and it implements INotifyPropertyChanged, I wanted to add properties to this type at runtime, so a getter and a setter and the setter would call a method Notify passing in it's property name i.e
public string Name
{
get { return _name; }
set
{
_name = value;
NotifyPropertyChanged("Name");
}
}
Yes, but not with "normal" CLR types. You can achieve that, actually that type was created especially for functionalities like that: DynamicObject
Look on example code provided of the class that implements DynamicObject, like
public class DynamicDictionary : DynamicObject
{
...
}
and after you are able to use it like:
dynamic person = new DynamicDictionary();
// Adding new dynamic properties.
person.FirstName = "Ellen";
person.LastName = "Adams";
You can use Reflection.Emit to dynamically create new classes that inherit from your class, and then add the properties to that new type.
As it inherits your own type, it can be considered as being an "extension" for that type.
I must warn you that this path is a complicated one, and you will probably produce code that you will never understand again after finishing the job!
Also you will have understand how MSIL code works. It is a bit odd, and inverted thing. You have to do things quite the oposite way you would expect in a language such as C#. You must push and pop values from stacks to pass as argument to a function, and you must activelly discard unused return values from functions... and so on.
And YES, I am trying to make you afraid of this... it is such a painful way ;)
Consider other alternatives before falling to this one.
There is a lot of material in SO already on this matter: https://stackoverflow.com/questions/tagged/reflection.emit
CodeProject article explaining Reflection.Emit:
Dynamic Type Using Reflection.Emit
Either you use a Dynamic Object or extend behavior via Extension Methods. I don't know of other options.
no, that is not possible with c# objects
you can make dictionary like classes, which can store different properties like in the question with the DynamicObject
what you can do is is creating new class types by reflection, and they can contain new properties. but there is no easy way to access these
I have two classes like this:
public abstract class MyBase
{
protected MyBase(){
Initialize();
}
protected IDictionary<string,string> _data;
private void Initialize() {
// Use Reflection to get all properties
// of the derived class (e.g., call new MyDerived() then
// I want to know the names "Hello" and "ID" here
var data = GetDataFromBackend(propertyNamesFromDerived);
_data = data;
}
}
public class MyConcrete : MyBase
{
public MyConcrete(){
// Possibly use Reflection here
Hello = _data["Hello"];
ID = new Guid(data["ID"]);
}
public string Hello {get;set;}
public Guid ID {get; set;}
}
As you see, I want the constructor of my base class to know about the properties of the derived class I'm instantiating.
Now, this seems like a huge and big code smell, so let me give some more background about my intentions, maybe there is a better way.
I have a backend system that stores Key/Value Pairs, essentially a Dictionary<string,string>. I want to abstract away working with this backend system in a way where people can create classes whose properties are Keys into the backend system. When they construct this object, it will automatically load the data from that system and initialize all the variables to it.
In other words, I've just reinvented serialization, except that I don't control the backend system and just rather make working with it really painless. I don't want callers to have to call Initialize() after constructing the object, because in 100% of the cases you have to initalize it after constructing.
I don't want to move the initialize code into the Derived Classes, except for string-to-business-object conversion.
Would I have to use a Factory? Or is it considered safe to look at the property names of a derived class in a base constructor? (Don't care about their values and that they aren't initialized, just need the names).
Or is there a better way altogether to provide a facade between a Dictionary of strings and a concrete business object?
Edit: This is .net 3.5, so no System.Dynamic which would make this trivial :(
Edit 2: After looking at the Answers and thinking through this some more, I guess my question really boils down to this now: Is calling GetType().GetProperties() from a base constructor in order to get the Names of Properties and if they are decorated with a certain Attribute safe?
Wait, let's stop here for a second and do this properly. It shouldn't be MyBase's responsibility to do this.
So you write a class that manages getting stuff out of the backend for you, and you write a method on that class that is something like
T Get<T>() where T : new()
and you make Get responsible for reading the dictionary out of the backend and using reflection to populate an instance of T. Thus, you say
var concrete = foo.Get<MyConcrete>();
This isn't hard, and it's the right way to do it.
Incidentally, the code for Get is going to look something like
T t = new T();
var properties = typeof(T).GetProperties();
foreach(var property in properties) {
property.SetValue(t, dictionary[property.Name], null);
}
return t;
where dictionary is your loaded up key/value pairs. It turns out there are more optimal ways to do this, but unless it's a bottleneck I wouldn't worry about it.
The better way to do this would be to make the classes use the dictionary directly:
public string Hello {
get { return (string)base.data["Hello"]; }
set { base.data["Hello"] = value; }
}
You may want to call TryGetValue in the getter so that you can return a default value if the key isn't there. (You should probably do that in a separate method in the base class)
You can make a code snippet to make the properties easier to create.
If you don't want to do it this way, you can call GetType().GetProperties() to get PropertyInfo objects for the properties in your class, then call SetValue(this, value).
This will be slow; there are various tricks you can use to speed it up using expression trees, CreateDelegate, or IL generation.
Maybe try the Template method pattern
Have you considered using an ExpandoObject? With it you can dynamically add properties and inspect them (when serializing for example).
I'm not sure if it's what you really should do, but here's what you asked for (put this in Initialize, and you'll get a list of the derived property names):
var derivedProps = this.GetType().GetProperties();
var propNames = new List<string>(derivedProps.Select(x => x.Name));
From there, using the PropertyInfos in derivedProps, you can set the properties.
You can't really safely do anything to those properties in the base-class constructor anyway as some derived constructor may reset them anyway. You're much better off doing a two-phased load (e.g. call Initialize explicitly)