动态生成泛型对象字段
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 讨论了使用它比直接进行反射调用的好处。
代码:
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 讨论了使用它比直接进行反射调用的好处。