English 中文(简体)
Question about reading properties of a class at run time in c# (.NET 2.0)?
原标题:

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)  // ???
最佳回答

Answered a similar question earlier. Here s a code sample, and link to the other question. Hiding Public Functions

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
问题回答

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.

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();

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.

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.

string propertyToGet = "SomeProperty";
SomeClass anObject = new SomeClass();

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

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];




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签