|
I am attempting to make a method such as the following:
1 public static void foo<T>(T unknown) {
2 PropertyInfo[] tProps = typeof(T).GetProperties();
3 foreach (PropertyInfo pi in tProps) {
4 foo<pi.PropertyType>(pi.GetValue(unknown, null));
5 }
6 } I get the following compiler error on line 4: "The type or namespace name 'pi' could not be found (are you missing a using directive or an assembly reference?)". Is there any way for me to recursively call this method as logically indicated by the code above? Thanks,
Sounds like somebody's got a case of the Mondays
-Jeff
|
|
|
|
|
You need to know the Type at compile time.
|
|
|
|
|
I found that ComboBox does not allow to enter data using foreign keys.
To reproduce:
1. Run code
2. Enter Walter from keyboard
3. Click button.
Observed:
J
Expected:
W
How to fix ?
using System.Windows.Forms;<br />
using System.Collections.Generic;<br />
<br />
class testForm : Form {<br />
<br />
Storage s = new Storage();<br />
<br />
testForm() {<br />
Customer c = new Customer();<br />
c.Id = "J";<br />
c.Name = "John";<br />
<br />
List<Customer> l = new List<Customer>();<br />
l.Add(c);<br />
c = new Customer();<br />
c.Id = "W";<br />
c.Name = "Walter";<br />
l.Add(c);<br />
<br />
ComboBox cm = new ComboBox();<br />
cm.DisplayMember = "Name";<br />
cm.ValueMember = "Id";<br />
cm.DataSource = l;<br />
<br />
s.CustId = "W";<br />
<br />
cm.DataBindings.Add("SelectedValue", s, "CustId");<br />
<br />
Controls.Add(cm);<br />
Button b = new Button();<br />
b.Top = 80;<br />
b.Click += new System.EventHandler(b_Click);<br />
Controls.Add(b);<br />
<br />
}<br />
<br />
void b_Click(object sender, System.EventArgs e) {<br />
if (s.CustId == null)<br />
MessageBox.Show("Empty combobox must store null value");<br />
else<br />
MessageBox.Show(s.CustId.ToString());<br />
<br />
}<br />
<br />
class Customer {<br />
public string Id { get; set; }<br />
public string Name { get; set; }<br />
<br />
}<br />
<br />
class Storage {<br />
public string CustId { get; set; }<br />
}<br />
<br />
static void Main() {<br />
Application.Run(new testForm());<br />
}<br />
}
Andrus
|
|
|
|
|
When you type in Walter, the items bound are not selected. You can either set the drop down style to DropDownList, forcing user to select from the list, or you can use a custom control that "search" for "Walter" in the list while you type, and set the selected index if it is able to match the serach. IIRC there's such a combobox here on CodeProject.
|
|
|
|
|
If I have these classes...
public class TestClass
{
}
public class TestCollection : List<TestClass>
{
}
... and I pass an instance of the TestCollection class to this...
public static void MyMethod(object ListObject)
{
}
... I can use reflection to get loads of info about the TestCollection (ListObject) class.
What I can't figure out is how to use reflection to get the <T> (in this case TestClass) as this is the class I need to know about the properties for.
Dave
modified on Monday, December 17, 2007 3:38:19 PM
|
|
|
|
|
Hopefully this code will help you reflect on the problem (pun semi-intended):
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace GenericReflection
{
class Program
{
static void Main(string[] args)
{
List<int> intList = new List<int>();
DisplayGenericInformation(intList);
}
static void DisplayGenericInformation(object genericObject)
{
DisplayGenericInformation(genericObject, 0);
}
static void DisplayGenericInformation(object genericObject, int indent)
{
Type genericObjectType = genericObject.GetType();
WriteIndented(genericObjectType.Name, indent);
foreach (Type argumentType in genericObjectType.GetGenericArguments())
{
WriteIndented(argumentType.Name, indent + 1);
DisplayGenericInformation(argumentType, indent + 2);
}
}
static void WriteIndented(string message, int indent)
{
while ((indent--) > 0)
{
Console.Write(" ");
}
Console.WriteLine(message);
}
}
}</int></int>
|
|
|
|
|
Thanks, it's helped a little but there is still a problem as commented in this ammended version of the code you supplied.
using System;
using System.Collections.Generic;
using System.Reflection;
namespace GenericReflection
{
class Program
{
class MyClass
{ }
class MyCollection : List<MyClass>
{ }
static void Main(string[] args)
{
List<MyClass> intList1 = new List<MyClass>();
DisplayGenericInformation(intList1);
Console.WriteLine(Environment.NewLine);
MyCollection intList2 = new MyCollection();
DisplayGenericInformation(intList2);
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
static void DisplayGenericInformation(object genericObject)
{
DisplayGenericInformation(genericObject, 0);
}
static void DisplayGenericInformation(object genericObject, int indent)
{
Type genericObjectType = genericObject.GetType();
WriteIndented(genericObjectType.Name, indent);
foreach (Type argumentType in genericObjectType.GetGenericArguments())
{
WriteIndented(argumentType.Name, indent + 1);
DisplayGenericInformation(argumentType, indent + 2);
}
}
static void WriteIndented(string message, int indent)
{
while ((indent--) > 0)
{
Console.Write(" ");
}
Console.WriteLine(message);
}
}
}
|
|
|
|
|
That makes sense because you'd need to look at the base type information for the classes. Since I don't really know what the structure of the code is like and what you're going to expect I can't provide a better example, but you could change it too something like:
using System;
using System.Collections.Generic;
using System.Reflection;
namespace GenericReflection
{
class Program
{
class MyClass
{ }
class MyCollection : List<myclass>
{ }
static void Main(string[] args)
{
List<myclass> intList1 = new List<myclass>();
DisplayGenericInformation(intList1);
Console.WriteLine(Environment.NewLine);
MyCollection intList2 = new MyCollection();
DisplayGenericInformation(intList2);
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
static void DisplayGenericInformation(object genericObject)
{
DisplayGenericInformation(genericObject, 0);
}
static void DisplayGenericInformation(object genericObject, int indent)
{
Type genericObjectType = genericObject.GetType();
WriteIndented(genericObjectType.Name, indent);
foreach (Type argumentType in genericObjectType.GetGenericArguments())
{
WriteIndented(argumentType.Name, indent + 1);
DisplayGenericInformation(argumentType, indent + 2);
WriteIndented("Base:" + argumentType.BaseClass.Name, indent + 1);
DisplayGenericInformation(argumentType.BaseClass, indent + 2);
}
}
static void WriteIndented(string message, int indent)
{
while ((indent--) > 0)
{
Console.Write(" ");
}
Console.WriteLine(message);
}
}
}</myclass></myclass></myclass>
|
|
|
|
|
Thanks for your efforts Ed.
If I explain what I'm trying to acheive it may make more sense!
In this application there are lots of individual classes eg.
public class Student
{
private int _ID;
private string _Name;
private DateTime _DOB;
public int ID
{
get { return _ID; }
set { _ID = value; }
}
public string Name
{
get { return _Name; }
set { _Name = value; }
}
public DateTime DOB
{
get { return _DOB; }
set { _DOB = value; }
}
}
Most of these also need a collection eg:
public class StudentCollection : List<student>;
{ }
I've been implementing the IComparer interface on the individual classes and doing recursive sorting on its properties using CompareTo but that means I have to write the CompareTo method for each individual class.
What I'm trying to do is to create a generic sorter method that accepts a collection object and recursively sorts it based upon the properties of the individual object that is contained in each index of the incoming object
public static void GenericCompare(object ListObject)
{
}
i hope this makes sense!
|
|
|
|
|
It does make sense but you seem to have a slightly odd way of going about it.
Quick question are you restricted on framework versions / compiler versions, e.g. are you using 2.0, 3.0, 3.5 framework and which compilers: 2005 or 2008?
Second point is that I recommend you reading this[^] fantastic article on "code generation" which will speed up things considerably because you're going to be doing a lot of reflection your way.
I'm thinking about a semi-ideal solution at the moment...
|
|
|
|
|
Ok I've whipped together a simple demo:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace ReflectionComparer
{
internal static class Program
{
[STAThread]
private static void Main(string[] args)
{
var students = new StudentCollection();
var teachers = new TeacherCollection();
students.AddRange(new Student[] {
new Student() { ID = 1, Name = "Edward Poore", DOB = new DateTime(1988, 4, 7) },
new Student() { ID = 2, Name = "Joe Smith", DOB = new DateTime(2001, 5, 6) },
new Student() { ID = 3, Name = "Davey M69", DOB = new DateTime(2006, 11, 25) }
});
teachers.AddRange(new Teacher[] {
new Teacher() { ID = 1, Name = "Eric Yeatman", DOB = new DateTime(1964, 10, 2), Department = "EEE" },
new Teacher() { ID = 2, Name = "Chris Maunder", DOB = new DateTime(1972, 3, 19), Department = "CS" },
new Teacher() { ID = 3, Name = "Marc Clifton", DOB = new DateTime(1984, 5, 1), Department = "BIOL" }
});
DisplayInformation(students);
DisplayInformation(teachers);
}
private static void DisplayInformation(object collection)
{
var list = (collection as IEnumerable);
var enumerator = list.GetEnumerator();
if (enumerator.MoveNext() == true)
{
Sort(list, enumerator.Current.GetType());
}
}
private static void Sort(IEnumerable collection, Type objectType)
{
Console.WriteLine(objectType.Name);
foreach (var property in objectType.GetProperties())
{
Console.WriteLine(" {0}", property.Name);
}
}
}
}
Student , Teacher are simple classes which define ID, Name and DOB (Teacher also includes department). The collection classes all inherit from List>T< .
I'm sorry the code uses 3.5 syntax but it saves so much typing and is so elegant I can't resist using it, hopefully things are fairly clear. The one thing that is not clear from your examples is how you decide which properties to sort on. If it were a simple are they the same test then you would simply check all properties are equal but I don't understand how you decide which one takes preference over the other (unless you specify it to the sorter routine).
|
|
|
|
|
Thanks Ed, this does exactly what I wanted.
I have no restriction on framework and I'm currently using 3.5.
Once I have the properties of the class (which your code gives me) the sort is pretty easy as the method will also be passed a parameter stating which property to begin at, a little error checking, then recursively sort from there to the end of the remaining properties and the job's done. This is assuming that the properties are always returned in the order they are defined in the class - I haven't found any documentation on this but it appears so from my experiments.
The article you linked to is FASCINATING! It looks like the way to go. It'll keep me busy over xmas I'm sure.
Once again, many thanks for all your time and help.
Edit: I can't vote on your last reply as there's something gone wrong in the formatting - I had this with my previous post and had to view the html source to get the hyperlink to use to be able to edit it.
I voted on your initial reply instead.
modified on Wednesday, December 19, 2007 6:47:10 AM
|
|
|
|
|
If you want my full solution it's here[^].
Created with VC# 2008 (am waiting for Imperial to get VS2008 Pro through their campus agreement).
Just had another thought, you could use attributes to set the sort order of properties, if the attribute doesn't exist then don't sort. Something like:
[Sort(0, SortOrder.Ascending)]
public string Name { get; set; }
[Sort(1, SortOrder.Descending)]
public DateTime DOB { get; set; }
(Example uses automatic properties, a fantastic feature).
DaveyM69 wrote: The article you linked to is FASCINATING! It looks like the way to go. It'll keep me busy over xmas I'm sure.
It certainly is, I experimented with it for a rewrite of a DAL that I wrote for a company I worked for but LINQ seems to have more or less knocked this method on the head. Although it would be a very cool way to go.
It's these kind of problems which I enjoy helping out in, what with my degree and so on I don't have that much time for programming and that which I do do has been in Pascal and Assembler for the course (although I don't do any extra-curricular stuff like my fellows since it's simply a change of framework and syntax). And god-forbid in the near future some Java, I was offered a job by one of my lecturers at Imperial (Software Engineering lecturer, originally from the Computer Science department but now lecturing for Electrical & Electronic Engineering) and this unfortunately is in Java
|
|
|
|
|
A new and updated project[^] has been uploaded.
Sorry if it took the fun away from you but I needed something to relax ( ) my mind so continued with the Three Monkeys approach and have implemented the suggestions I made earlier. (I don't know whether this is possible in your case): but if you inherit your "data" class from ComparableObject then unless the CompareTo method is overridden it automatically compares itself through "reflection".
To allow this you tag each of your properties with a SortAttribute specifying the priority in which the properties are to be sorted, see code for examples. The method which builds the DynamicMethod looks for these attributes (using a piece of LINQ, making it sooo much easier, and ordering them in order of the priority). It then basically goes through and generates the IL for making the comparison, as if you'd typed it out yourself.
These dynamic methods are stored in a Dictionary<TKey,TValue> so that subsequent calls don't hit the performance penalty of performing reflection.
Quite a handy piece of code actually, might write it up into an article...
[BTW]Thanks for providing me with something "challenging" to do in C#[/BTW]
|
|
|
|
|
Cool! Very cool actually. This is one of those things that initially you think 'why does he want to do that?', but the more you think about it, it makes sense.
The amount of times I've had to write custom comparers so I can sort on either one particular property or recursively sort on many, I figured there had to be a way of implementing a more Generic one.
I developed one that worked but you had to pass a string array containing the properties you wished to sort on. It just felt a bit clumsy as the properties were already defined in the class so why was I having to restate them?
Marvellous work.
Ed.Poore wrote: [BTW]Thanks for providing me with something "challenging" to do in C#[/BTW]
- no problem
|
|
|
|
|
Well I've tidied the code up a bit and got it into article form, now just got to write the damn article...
|
|
|
|
|
Hi,
I want to translate a word using Babylon In my Application, is it possible?
i.e. I want in my app word sends to babylon and get translation.
Should I crack babylone for it?
Please give me general help about it.
Best wishes
|
|
|
|
|
Since this is a question about 3rd party software, you probably won't get an answer in this forum. Have you contacted Babylon support and asked if they have a developer API available?
|
|
|
|
|
I would advise against 'cracking' babylon. As that is illegal.
Also, what you would be doing wouldn't really be a crack... and i question your ability to do it. Either way, still illegal.
My current favourite word is: Bauble!
-SK Genius
|
|
|
|
|
I inherited a usercontrol from the System.Windows.Form but when i assigned it to the PropertyGrid control it inherits all the Form Properties and display in the PropertyGrid. How can I display on the properties which are declared in my usercontrol.
|
|
|
|
|
I think you are asking, "How can I hide the UserControl properties from being displayed in a PropertyGrid control?" The answer to this question is by overloading the appropriate property and setting the Browsable attribute of your property to false:
[Browsable(false)]
public override string Text {
get { return base.Text; }
set { base.Text = value; }
} If this didn't answer your question, you need to rephrase, because I can't understand what you are asking for.
Sounds like somebody's got a case of the Mondays
-Jeff
|
|
|
|
|
|
See my answer to the post below to find out how to do this.
|
|
|
|
|
Hi,
is it possible to remove a property from a inherited control?
for example if i inherit a textbox and i want to remove the "Text" property, is it possible?
|
|
|
|
|
Hi
No you can not remove a Property,
but i think System.ComponentModel.BrowsableAttribute should do the job:
[Browsable(false)]
public override string Text
{
get{}
set{}
}
hope this helps
greets
M@u
|
|
|
|
|