簡體   English   中英

C#-如何在不使用反射的情況下獲取/設置對象的屬性值

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM