views:

140

answers:

7

Let's say I have a class that has 3 properties. I don't know which property I want to read until runtime. Is there a way to do this without a switch/if-else statement?

If a DataTable is treated as a class, then the columns can be treated dynamically which would work, but I'm not able to change my class into a DataTable (long story).

For a DataTable, the code would be:

string columnName = "Age";
int age = dataRow[columnName];

How is this possible in a class?

string propertyName = "Baka";
int age = item.getProperty(propertyName)  // ???
+2  A: 

The easiest way to do this kind of runtime evaluation is with Reflection.

Depending on the version of .NET you're using, you could add methods to your class or use extension methods.

Dave Swersky
what are the other ways?
Russ Cam
Reflection is the only practical way I know to get a property when you don't know which one you want until runtime. Other methods could include some kind of value dictionary but Reflection will always work and can be applied without mucking up your classes with extra stuff.
Dave Swersky
A: 

Answered a similar question earlier. Here's a code sample, and link to the other question. http://stackoverflow.com/questions/1754516/hiding-public-functions/1755672#1755672

You're going to be most interested in the GetValue method of the System.Reflection.PropertyInfo class.

C# Code Sample

public bool SetProperty(object obj, string PropertyName, object val)
{
    object property_value = null;
    System.Reflection.PropertyInfo[] properties_info = obj.GetType.GetProperties;
    System.Reflection.PropertyInfo property_info = default(System.Reflection.PropertyInfo);
    
    foreach (System.Reflection.PropertyInfo prop in properties_info) {
        if (prop.Name == PropertyName) property_info = prop; 
    }
    
    if (property_info != null) {
        try {
            property_info.SetValue(obj, val, null);
            return true;
        }
        catch (Exception ex) {
            return false;
        }
    }
    else {
        return false;
    }
}

public object GetProperty(object obj, string PropertyName)
{
    object property_value = null;
    System.Reflection.PropertyInfo[] properties_info = obj.GetType.GetProperties;
    System.Reflection.PropertyInfo property_info = default(System.Reflection.PropertyInfo);
    
    foreach (System.Reflection.PropertyInfo prop in properties_info) {
        if (prop.Name == PropertyName) property_info = prop; 
    }
    
    if (property_info != null) {
        try {
            property_value = property_info.GetValue(obj, null);
            return property_value;
        }
        catch (Exception ex) {
            return null;
        }
    }
    else {
        return null;
    }
}

VB Code Sample

Public Function SetProperty(ByVal obj As Object, ByVal PropertyName As String, ByVal val As Object) As Boolean
    Dim property_value As Object
    Dim properties_info As System.Reflection.PropertyInfo() = obj.GetType.GetProperties
    Dim property_info As System.Reflection.PropertyInfo

    For Each prop As System.Reflection.PropertyInfo In properties_info
        If prop.Name = PropertyName Then property_info = prop
    Next

    If property_info IsNot Nothing Then
        Try
            property_info.SetValue(obj, val, Nothing)
            Return True
        Catch ex As Exception
            Return False
        End Try
    Else
        Return False
    End If
End Function

Public Function GetProperty(ByVal obj As Object, ByVal PropertyName As String) As Object
    Dim property_value As Object
    Dim properties_info As System.Reflection.PropertyInfo() = obj.GetType.GetProperties
    Dim property_info As System.Reflection.PropertyInfo

    For Each prop As System.Reflection.PropertyInfo In properties_info
        If prop.Name = PropertyName Then property_info = prop
    Next

    If property_info IsNot Nothing Then
        Try
            property_value = property_info.GetValue(obj, Nothing)
            Return property_value
        Catch ex As Exception
            Return Nothing
        End Try
    Else
        Return Nothing
    End If
End Function
brad.huffman
Converted code sample to C# with http://www.developerfusion.com/tools/convert/vb-to-csharp/
brad.huffman
A: 

item.GetProperties() would return a PropertyInfo[] containing all properties (public only I think)

A PropertyInfo Object has a property Name which is the name of the property, so you can iterate over the array searching for a PropertyInfo object with your search name.

cdkMoose
+1  A: 

If you know the type of object you can get all the properties, and then your requested property, using reflection.

MyClass o;

PropertyInfo[] properties = o.GetType().GetProperties(
    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

Each PropertyInfo has a Name which you can match up to your String.

David Liddle
+2  A: 

EDIT: I just read your comment about not using a switch, but I'll keep this here anyway, just in case... skip to my second answer.

Maybe something like this:

public enum Property { Name, Age, DateOfBirth};

public T GetProperty<T>(Property property)
{
    switch (property)
    {
       case Property.Name:
          return this.Name;
       // etc.
    }
}

I'm not too strong in Genetics, so maybe someone can help me with the return cast.


Alternatively, you could add a field to your class of type DataRow and use an indexer to access it:

public class MyClass
{
   DataTable myRow = null;
   MyClass(DataRow row)
   {
      myRow = row;
   }

   public object this[string name]
   {
      get
      {
         return this.myRow[name];
      }
      set
      {
         this.myRow[name] = value;
      }
   }
}

Usage:

MyClass c = new MyClass(table.Rows[0]);
string name = c["Name"].ToString();
Philip Wallace
A: 
string propertyToGet = "SomeProperty";
SomeClass anObject = new SomeClass();

string propertyValue = 
    (string)typeof(SomeClass)
    .GetProperty("SomeProperty")
    .GetValue(anObject, null);
Joseph
A: 

Example using indexers:

public class MyItem
{
    public object this[string name]
    {
        switch (name)
        {
            case "Name":
                return "Wikipetan";
            case "Age":
                return 8;
            case "DateOfBirth":
                return new DateTime(2001, 01, 15);
            case "Baka":
                return false;
            default:
                throw new ArgumentException();
        }
    }
}

Usage:

MyItem item = ...;
string propertyName = "Age";
int age = (int)item[propertyName];
dtb