簡體   English   中英

在自動屬性中訪問支持字段

[英]Acessing the backing field in an auto property

有沒有辦法訪問屬性的支持字段,以便進行驗證,更改跟蹤等?

是否有類似以下內容? 如果沒有,是否有計划在.NET 4 / C#4中使用它?

public string Name
{
    get;
    set
    {
        if (value != <Keyword>)
        {
            RaiseEvent();
        }
        <Keyword> = value;
    }
}

我遇到的主要問題是使用自動屬性不允許在具有明確支持字段的屬性的驗證等方面具有相同的靈活性。 然而,顯式支持字段在某些情況下具有缺點,即允許其所包含的類在訪問和重用屬性的驗證,更改跟蹤等時訪問支持字段,就像可能正在訪問的任何其他類一樣外部的財產。

在上面的示例中,對支持字段的訪問將限定為屬性,從而防止繞過屬性驗證,更改跟蹤等。

編輯:我已將<Backing Field>更改為<Keyword>。 我會提出一個類似於價值的新關鍵字。 雖然我確信它在很多現有代碼中被使用,但是字段會很好。

不,沒有。 如果要訪問支持字段,請不要使用自動屬性並自行滾動。

我同意,擁有一個只能由財產而不是其他同類人員訪問的字段會很棒。 我會一直使用它。

正如MSDN所述:

“在C#3.0及更高版本中,當屬性訪問器中不需要額外的邏輯時,自動實現的屬性使屬性聲明更簡潔。它們還使客戶端代碼能夠創建對象當您聲明屬性時,如以下示例所示,編譯器創建一個私有的,匿名的后備字段只能通過屬性的get和set訪問器來訪問。“

由於在訪問器中有其他邏輯,因此在您的方案中使用自動實現的屬性是不合適的。

雖然支持字段確實存在,但它會被賦予一個錯誤的名稱以阻止您輕松引用它 - 這個想法是您永遠不會直接引用該字段 為了利益起見,您可以使用Reflector來反匯編代碼並發現字段名稱,但我建議您不要直接使用該字段,因為此名稱可能確實存在易變性,因此您的代碼可能隨時中斷。

在Mehrdad的回答中閱讀了你的評論后,我想我更了解你的問題。

您似乎擔心開發人員能夠在他們正在編寫的類中訪問私有狀態,繞過您的驗證邏輯等。這表明該狀態根本不應該包含在類中。

我會建議以下策略。 編寫表示ValidatedValue的泛型類。 此類僅包含后備值,並且僅允許通過get和set方法進行訪問/變異。 委托被傳遞給ValidatedValue以表示驗證邏輯:

public class ValidatedValue< T >
{
    private T m_val;
    public ValidationFn m_validationFn;

    public delegate bool ValidationFn( T fn );

    public ValidatedValue( ValidationFn validationFn )
    {
        m_validationFn = validationFn;
    }

    public T get()
    {
        return m_val;
    }

    public void set(T v)
    {
        if (m_validationFn(v))
        {
            m_val = v;
        }
    }
}

當然,您可以根據需要添加更多代理(例如,支持更改前/后通知)。

您的類現在將使用ValidatedValue代替您的屬性的后備存儲。

下面的示例顯示了一個類MyClass,其中一個整數被驗證為小於100.請注意,拋出異常的邏輯是在MyClass中,而不是ValidatedValue。 這允許您執行依賴於MyClass中包含的其他狀態的復雜驗證規則。 Lambda表示法用於構造驗證委托 - 您可以綁定到成員函數。

public partial class MyClass
{
    private ValidatedValue<int> m_foo;

    public MyClass()
    {
        m_foo = new ValidatedValue<int>(
            v => 
            {
                if (v >= 100) RaiseError();
                return true;
            }
        );
    }

    private void RaiseError()
    {
        // Put your logic here....
        throw new NotImplementedException();
    }

    public int Foo
    {
        get { return m_foo.get(); }
        set { m_foo.set(value); }
    }
}

希望有所幫助 - 有點偏離原始主題,但我認為它更符合您的實際問題。 我們所做的是將驗證邏輯從屬性中移除並將其放在數據上,這正是您想要的位置。

不,但你可以在一個子類中:

public class Base
{
    public string Name
    {
        get;
        virtual set;
    }
}

public class Subclass : Base
{
    // FIXME Unsure as to the exact syntax.
    public string Name
    {
        override set
        {
            if (value != base.Name)
            {
                RaiseEvent();
            }

            base.Name = value;
        }
    }
}

如果您要這樣做,為什么要使用汽車房產?!

一個簡單的屬性已經在1.0中完成了。 我不認為為每種特殊情況增加語言的復雜性是有意義的。 您需要該屬性來執行普通存儲/檢索模型或需要更多。 在后一種情況下,正常的財產會做。

你不能這樣做我害怕。 這是我開始編寫MoXAML Power Toys的原因之一,它提供了將自動屬性轉換為Notify屬性的能力。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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