动态生成泛型对象字段

Dynamically generate object field of generic type

代码:

objectType request = factory.create<objectType>();

public class factory
{
    public static T create<T>() where T : new()
    {
      T obj = new T();
      PropertyInfo propertyInfo = obj.GetType().GetProperty("client_no");
      propertyInfo.SetValue(obj, CLIENT_NUMBER, null);
      return (T)Convert.ChangeType(obj, typeof(T));
     }
}

解释:

我正在创建一个设置 2 个对象属性的通用工厂 fn()。

这些属性在我要初始化的所有对象中都是一致的。

1) 我如何调用我的函数

objectType request = factory.create<objectType>(); // <-- This works

1b) 如果我愿意,我可以从这里开始执行以下操作,但是在我的所有对象中都是重复的额外代码

request.client_no = CLIENT_NUMBER;

2) 下面是我的工厂 fn()

public static T create<T>() where T : new()
{
  T obj = new T();      

  // Here is where I am having trouble setting client_no I will explain in #3         

  return (T)Convert.ChangeType(obj, typeof(T)); // <-- This works returns generic type
}

3) 我试过 PropertyInfo 来设置对象属性如下

PropertyInfo propertyInfo = obj.GetType().GetProperty("client_no");
propertyInfo.SetValue(obj, CLIENT_NUMBER, null);

我也试过了this

obj.GetType().GetProperty("client_no").SetValue(obj, CLIENT_NUMBER, null); 

我试过了

T obj = new T();      
var t = typeof(T);
var prop = t.GetProperty("client_no");
prop.SetValue(obj, CLIENT_NUMBER);

4) 这是我收到的错误

Object reference not set to an instance of an object

More/Newer信息:

随着进一步的研究。第 3 方对象属性没有 getter 和 setter {get; set;} 这就是 GetType() 和 SetValue() 不起作用的原因。

我的同事指出 属性 是一个单一的任务 这就是为什么我们可以

request.client_no = CLIENT_NUMBER;

所以我的问题是如何设置这些属性?

使用反射,你可以做这样的事情:

public objectName updateAccountData(int accountId, Dictionary<string,string> accountData)
{
    var request = new objectName();
    var t = typeof(objectName);
    foreach (var k in accountData)
    {
        var prop = t.GetProperty(k.Key);   // you might want to check property exists before trying to set it
        prop.SetValue(request,k.Value);
    }
    return request;
}

这假设您的 objectName class 已经拥有您需要填充的所有属性。

请注意,反射比直接访问 属性 慢,因此如果此代码位于应用程序的性能关键部分,则可能存在问题(对其进行分析)。可以很容易地应用几个明显的优化。例如,您可以将从 GetProperty 检索到的所有 PropertyInfo 对象存储在 Dictionary<string,PropertyInfo> 中,以避免必须继续查找它们。更复杂的是,您实际上可以使用表达式树来构建和编译表达式以供 属性 访问。

对于一个字段,只需将 t.GetField(k.Key) 替换为 GetProperty

如果您不知道它是字段还是 属性(或两者的混合),那么您可以使用 GetMember 然后检查 MemberType 以决定。

已解决。方法如下。

我的主要问题是理解错误,我试图设置的项目不是 属性,而是一个字段。

要自己更好地了解差异,您可以查看 this

这是我修复它的方法:

我设置了泛型的字段类型

public static T create<T>() where T : new()
{
  T obj = new T();

  Type myType = typeof(T);
  FieldInfo myFieldInfo = myType.GetField("client_no");
  myFieldInfo.SetValue(obj, CLIENT_NUMBER);                        

  return obj;
}

特别感谢@MattBurland,他指引了我正确的方向。

我看到了接受的答案,但是,这是另一种不涉及直接调用反射而是使用 DLR 的方法。

  public static T create<T>() where T : new()
  {
     T obj = new T();
     ((dynamic)obj).client_no = CLIENT_NUMBER;
     return obj;
  }

MSDN Dynamic Language Runtime Overview

这里的重要部分是编译器会处理它,而不是您自己编写反射调用。上面的 link 讨论了使用它比直接进行反射调用的好处。