views:

611

answers:

3

I have a project in which I have to get all the variables from a struct in a different class and add all their names to a combo box in a form. My primary issue at the moment is iterating through the struct in a way that I can add each variable individually to the combo box. I tried doing this:

        msgVars vars = new msgVars();
        foreach (object obj in vars)
        {
            comboBox1.Items.Add(GetName(obj));
        }

but as you probably know, you can't iterate through a struct that way. Is there any way I can do this without hardcoding the variables in?

Also, for reference, this is the GetName function:

static string GetName<T>(T item) where T : struct
{
    var properties = typeof(T).GetProperties();
    if (properties.Length == 1)
    {
        return properties[0].Name;
    }
    else
    {
        return null;
    }
}
A: 

If you are looking for a way to access properties of a struct (or class) at runtime without predefining in code that set of properties, what you probably need to use is reflection.

Here's an example:

struct MyStruct
{
    private readonly int m_Age;
    private readonly string m_LastName;
    private readonly string m_FirstName;

    public int Age { get { return m_Age; } }
    public string LastName { get { return m_LastName; } }
    public string FirstName { get { return m_FirstName; } }

    public MyStruct( int age, string last, string first )
    {
        m_Age = age;
        m_LastName = last;
        m_FirstName = first;
    }
}

class StructReflection
{
    public static void Main(string[] args)
    {
        var theStruct = new MyStruct( 40, "Smith", "John" );
        PrintStructProperties( theStruct );
    }

    public static void PrintStructProperties( MyStruct s )
    {
        // NOTE: This code will not handle indexer properties...
        var publicProperties = s.GetType().GetProperties();
        foreach (var prop in publicProperties)
            Console.WriteLine( "{0} = {1}", prop.Name, prop.GetValue( s, null ) );
    }
}
LBushkin
A: 

You could try using Reflection. How about storing the information in a Hashtable.

public Hashtable GetPropertyInfo(Person person)
{
    var properties = new Hashtable();
    PropertyInfo[] propInfo = person.GetType().GetProperties();
    foreach (PropertyInfo prop in propInfo)
    {
         properties.Add(prop.Name, prop.GetValue(person, null));
    }

    return properties;
}

Then you could write the information out via:

var person = new Person()
Person.Name = "Test";
Person.Age = 21;

var PropertyInfo = GetPropertyInfo(person);
foreach (string key in PropertyInfo.Keys)
{
     Console.WriteLine("{0} = {1}", key, PropertyInfo[key]);    
}
James
A: 

A struct is a single entity, not a collection of variables. This means that you can't 'iterate' over its properties. What you need to do is get a collection of the property names and iterate over it. Your GetName function can't do this because it just returns the name of the first property.

To add the property names to a combo all you have to do is:

 var vars = new msgVars();
 foreach(var name in GetNames(vars))
     comboBox1.Items.Add(name);

In fact, getting the property name is so easy that you could get rid of GetNames completley and just write

  foreach (var prop in typeof(msgVars).GetProperties())
      comboBox1.Items.Add(prop.Name);

There are various ways you can write GetNames to return a collection of names. You can fill a List with the property names although the simplest is to have it return an iterator like this:

 public static IEnumerable<string> GetNames<T>(T obj) where T:struct
 {
     var properties = typeof (T).GetProperties();
     foreach (var propertyInfo in properties)
     {
         yield return propertyInfo.Name;
     }
 }

Finally, you don't really need to pass an instance of your struct to the method, as you are enumerating the structs property names, not their values. You can rewrite GetNames like this

 public static IEnumerable<string> GetNames<T>() where T:struct
 {
     var properties = typeof (T).GetProperties();
     foreach (var propertyInfo in properties)
     {
        yield return propertyInfo.Name;
     }
  }

and load the names like this

  foreach(var name in GetNames<msgVars>())
      comboBox1.Items.Add(name);
Panagiotis Kanavos