[英]Using C# Reflection, how to get Object's properties and their values if that Object is a property of Object that is inside of the List
[英]C# - How to get/set an object's property value without using Reflection
我需要能够存储对对象属性的引用,以便以后读取/写入对象,理想情况下无需使用反射。 我也愿意接受同样适用的设计模式,但是性能至关重要,因为我的应用程序将在各种“父”类上进行数百万次的“运行”调用。 下面的代码模板应解释我要做什么。
我想保持它的状态,以使我“需要”的变量是Child类的对象属性,而不是存储在某些列表中的数据结构。
最后,我认为我正在寻找的东西不仅限于重置对象值或检查是否为非null。 例如,在调用_run之后,Parent可能会将属性的值用于其他内容。
谢谢。
class requiredAttribute : Attribute
{
}
abstract class Parent
{
abstract protected void _run();
public Parent() {
// This can do whatever set-up is necessary in order to make the below run() call
// not need reflection.
/* What code goes here? */
}
public void run() {
// This code should reset all 'required' properties to null.
/* What goes here? */
_run();
// This code needs to ensure any required property is now not null.
// If it finds a null one, it should throw.
/* What goes here? */
}
}
class Child : Parent
{
[required]
protected object value1;
[required]
protected object value2;
// not required..
protected object value3;
protected void _run() {
// This must set all 'required' properties' values, otherwise the Parent should throw.
value1 = "some value";
value2 = "some other value";
}
}
我将使用接口而不是使用an属性。
创建一个可IValidatable
的接口并将其放置在父接口上。
给父母一个抽象的实现。 并在孩子身上实施它。
abstract class Parent : IValidatable
{
public abstract bool IsValid();
abstract protected void _run();
public Parent()
{
}
public void run()
{
_run();
if (!IsValid())
//throw
}
}
class Child : Parent
{
protected object value1;
protected object value2;
// not required..
protected object value3;
protected override void _run()
{
// This must set all 'required' properties' values, otherwise the Parent should throw.
value1 = "some value";
value2 = "some other value";
}
public override bool IsValid()
{
return value1 != null && value2 != null;
}
}
public interface IValidatable
{
bool IsValid();
}
我找到了一个运行良好的高性能反射库: FastMember 。
using FastMember;
class RequiredAttribute : Attribute
{
}
abstract class Parent
{
abstract protected void _run();
private List<string> required_prop_names = new List<string>();
private ObjectAccessor accessor;
public Parent()
{
// create list of properties that are 'required'
required_prop_names = this.GetType().GetFields()
.Where(prop => Attribute.IsDefined(prop, typeof(RequiredAttribute)))
.Select(prop => prop.Name)
.ToList<string>();
// create FastMember accessor
accessor = ObjectAccessor.Create(this);
}
public void run()
{
// set all to null
required_prop_names.ForEach(x => accessor[x] = null);
// call child
_run();
// validate
foreach (string prop_name in required_prop_names){
Console.WriteLine("Value of {0} is {1}", prop_name, accessor[prop_name]);
if (accessor[prop_name] == null){
Console.WriteLine("Null value found on {}!", prop_name);
}
}
}
}
class Child : Parent
{
[Required]
public object value1 = "something";
[Required]
public object value2 = "something";
// not required..
public object value3;
override protected void _run()
{
// This must set all 'required' properties' values, otherwise the Parent should throw.
value1 = "something else";
//value2 = "something else";
}
}
另一种解决方案使用包装器对象-这样,我们可以存储对这些对象的引用,并在以后获取/设置它们。 为了方便起见,包装对象可以由基础对象使用反射自动创建。 唯一的问题是在_run()内部,您必须执行value1.value =“ some value”而不是value1 =“ some value”。 公平贸易,IMO。
此解决方案仅需要在实例化时进行反思,并且仍然可以维护类型(出于智能感知的考虑)
代码看起来像这样..尚未测试,但这是一般的想法。
class Wrapper {
public object value;
}
class Wrapper<T> : Wrapper {
new public T value;
}
class requiredAttribute : Attribute
{
}
abstract class Parent
{
abstract protected void _run();
private List<Wrapper> wrappers = new List<Wrapper>();
public Parent() {
// Use reflection to find all fields that have a 'required' attribute.
// For each one, instantiate an instance of Wrapper<T>
// Store the reference to each object so that in run() we can reset and validate.
/* code that does above statement goes here. */
}
public void run() {
foreach (Wrapper wrapper in wrappers){
wrapper.value = null;
}
_run();
foreach (Wrapper wrapper in wrappers){
if (wrapper.value == null) throw new Exception("null value found");
}
}
}
class Child : Parent
{
[required]
protected Wrapper<string> value1;
[required]
protected Wrapper<int> value2;
// not required..
protected object value3;
protected void _run() {
// This must set all 'required' properties' values, otherwise the Parent should throw.
value1.value = "some value";
value2.value = 123;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.