我试图在我的代码中使用Reflection1示例实现数据转换。

GetSourceValue函数有一个比较各种类型的开关,但我想删除这些类型和属性,并让GetSourceValue只使用一个字符串作为参数来获取属性的值。我想在字符串中传递一个类和属性,并解析属性的值。

这可能吗?

1原始博客文章的Web存档版本


当前回答

在. net Standard中调用的方法已经改变(从1.6开始)。我们还可以使用c# 6的空条件操作符。

using System.Reflection; 
public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}

其他回答

public class YourClass
{
    //Add below line in your class
    public object this[string propertyName] => GetType().GetProperty(propertyName)?.GetValue(this, null);
    public string SampleProperty { get; set; }
}

//And you can get value of any property like this.
var value = YourClass["SampleProperty"];

下面的代码是一个递归方法,用于显示对象实例中包含的所有属性名称和值的整个层次结构。这个方法在这个线程中使用了AlexD的GetPropertyValue()答案的简化版本。多亏了这个讨论帖,我才知道该怎么做!

例如,我使用这个方法来显示WebService响应中所有属性的爆炸或转储,如下所示:

晚点属性(“响应”、“响应”、“错误”);

public static object GetPropertyValue(object srcObj, string propertyName)
{
  if (srcObj == null) 
  {
    return null; 
  }
  PropertyInfo pi = srcObj.GetType().GetProperty(propertyName.Replace("[]", ""));
  if (pi == null)
  {
    return null;
  }
  return pi.GetValue(srcObj);
}

public static void PropertyValues_byRecursion(string parentPath, object parentObj, bool showNullValues)
{
  /// Processes all of the objects contained in the parent object.
  ///   If an object has a Property Value, then the value is written to the Console
  ///   Else if the object is a container, then this method is called recursively
  ///       using the current path and current object as parameters

  // Note:  If you do not want to see null values, set showNullValues = false

  foreach (PropertyInfo pi in parentObj.GetType().GetTypeInfo().GetProperties())
  {
    // Build the current object property's namespace path.  
    // Recursion extends this to be the property's full namespace path.
    string currentPath = parentPath + "." + pi.Name;

    // Get the selected property's value as an object
    object myPropertyValue = GetPropertyValue(parentObj, pi.Name);
    if (myPropertyValue == null)
    {
      // Instance of Property does not exist
      if (showNullValues)
      {
        Console.WriteLine(currentPath + " = null");
        // Note: If you are replacing these Console.Write... methods callback methods,
        //       consider passing DBNull.Value instead of null in any method object parameters.
      }
    }
    else if (myPropertyValue.GetType().IsArray)
    {
      // myPropertyValue is an object instance of an Array of business objects.
      // Initialize an array index variable so we can show NamespacePath[idx] in the results.
      int idx = 0;
      foreach (object business in (Array)myPropertyValue)
      {
        if (business == null)
        {
          // Instance of Property does not exist
          // Not sure if this is possible in this context.
          if (showNullValues)
          {
            Console.WriteLine(currentPath  + "[" + idx.ToString() + "]" + " = null");
          }
        }
        else if (business.GetType().IsArray)
        {
          // myPropertyValue[idx] is another Array!
          // Let recursion process it.
          PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
        }
        else if (business.GetType().IsSealed)
        {
          // Display the Full Property Path and its Value
          Console.WriteLine(currentPath + "[" + idx.ToString() + "] = " + business.ToString());
        }
        else
        {
          // Unsealed Type Properties can contain child objects.
          // Recurse into my property value object to process its properties and child objects.
          PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
        }
        idx++;
      }
    }
    else if (myPropertyValue.GetType().IsSealed)
    {
      // myPropertyValue is a simple value
      Console.WriteLine(currentPath + " = " + myPropertyValue.ToString());
    }
    else
    {
      // Unsealed Type Properties can contain child objects.
      // Recurse into my property value object to process its properties and child objects.
      PropertyValues_byRecursion(currentPath, myPropertyValue, showNullValues);
    }
  }
}

使用微软的CallByName怎么样?VisualBasic命名空间(Microsoft.VisualBasic.dll)?它使用反射来获取普通对象、COM对象甚至动态对象的属性、字段和方法。

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

然后

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();

看看Heleonix。反映图书馆。你可以通过路径获取/设置/调用成员,或者创建一个getter/setter (lambda编译成委托),这比反射更快。例如:

var success = Reflector.Get(DateTime.Now, null, "Date.Year", out int value);

或者只创建一个getter并缓存以供重用(这样性能更好,但如果中间成员为空可能会抛出NullReferenceException):

var getter = Reflector.CreateGetter<DateTime, int>("Date.Year", typeof(DateTime));
getter(DateTime.Now);

或者如果你想创建一个List<Action<object, object>>的不同getter,只需要为已编译的委托指定基本类型(类型转换将被添加到已编译的lambdas中):

var getter = Reflector.CreateGetter<object, object>("Date.Year", typeof(DateTime));
getter(DateTime.Now);

关于嵌套属性的讨论,如果使用DataBinder,就可以避免所有反射的问题。Eval方法(对象,字符串)如下:

var value = DataBinder.Eval(DateTime.Now, "TimeOfDay.Hours");

当然,您需要添加对系统的引用。Web汇编,但这可能不是一个大问题。