簡體   English   中英

我可以在C#中創建動態接口嗎?

[英]Can I make a dynamic interface in C#?

我創建了一個自定義類(DynamicItem),該類繼承了DynamicObject類,並且可以很好地與dynamic關鍵字一起使用。 DynamicItem還實現和接口,因為我知道某些屬性將始終存在,我對此的測試如下所示:

    [Test]
    public void InterfaceTest()
    {
        //Assign
        Item item = _db.GetItem(TargetPath);          

        dynamic d = new DynamicItem(item);
        IDynamicItem i = d as IDynamicItem;


        //Act
        string result = d.Title;
        string path = i.Path;

        //Assert
        Assert.AreEqual("awesome", result);
        Assert.AreEqual(item.Path, path);
    }

未在接口上定義“標題”屬性,而是動態調用該屬性。 在接口上定義了“路徑”屬性。

該測試通過,一切正常。 令我煩惱的是,我必須進行從動態到界面的轉換。 我想做的只是使用界面:

    [Test]
    public void InterfaceTest()
    {
        //Assign
        Item item = _db.GetItem(TargetPath);          

        IDynamicItem d = new DynamicItem(item);


        //Act
        string result = d.Title;
        string path = d.Path;

        //Assert
        Assert.AreEqual("awesome", result);
        Assert.AreEqual(item.Path, path);
    }

但是,如果我這樣做,編譯器會抱怨,因為它在接口上找不到“ Title”屬性。 有沒有一種方法可以在將接口作為編譯器接口的同時將其標記為動態的?

不,您不能創建動態界面。 接口是一組預定義的方法和屬性,使用/實現該接口的所有組件都在運行時知道這些方法和屬性。 如果組件實現了接口,則可以保證該接口的方法/屬性對組件的用戶可用。 只要新組件實現了相同的接口,它還可以用另一組件替換一個組件。

另一方面,動態對象沒有任何預定義的內容-它的布局是在運行時根據可能隨時間變化的條件生成的。 如果函數返回動態對象,則多次調用它可能會返回不同的動態對象(具有不同的屬性)。 當調用者調用此類函數時,無法保證返回對象的布局。 這與接口相反。

正如@SteveLillis所評論的那樣,很少需要實際的動態對象。 在大多數情況下,您可以只使用Dictionary<string, object> (或類似的方式)並獲得類型安全性更高的方法,該方法對於其他人來說不會造成混淆。 在多年的編程中,我只需要使用dynamic關鍵字2到3次-在所有其他情況下,正確選擇的數據結構就足夠了-靜態類型化和類型安全的(一定程度上)。

這是做您想做的事的一個可能例子:

public interface IMyDynamicItem
{
    string SomeItemName { get; set; }

    object this[int nFieldIndex] { get; set; }

    object this[string sFieldName] { get; set; }

    IList<string> FieldNames { get; }
}

public class MyDynamicItem : IMyDynamicItem
{
    private Dictionary<string, object> m_oFields = 
        new Dictionary<string, object> ();

    public string SomeItemName { get; set; }

    public object this[int nFieldIndex]
    {
        get
        {
            string sFieldName = FieldNames[nFieldIndex];

            return ( m_oFields[sFieldName] );
        }
        set
        {
            string sFieldName = FieldNames[nFieldIndex];

            m_oFields[sFieldName] = value;
        }
    }

    public object this[string sFieldName]
    {
        get
        {
            return ( m_oFields[sFieldName] );
        }
        set
        {
            m_oFields[sFieldName] = value;
        }
    }

    public IList<string> FieldNames
    {
        get
        {
            return ( new List<string> ( m_oFields.Keys ) );
        }
    }
}

我不確定這是否是最好的方法,但這會大致為您提供您想要達到的目標,但它不理想-可以通過點表示法(即oItem.SomeItemName )訪問真正的接口成員,但是動態成員只能通過索引器符號( oItem[2]oItem["SomeField"] )進行訪問。

可以將接口成員添加到內部字典中,以便可以通過索引器符號查找所有成員-我個人覺得這種方法很臟。 在這種情況下,我可能只是將動態字段分離成一個真正的字典,而不是試圖維持這樣的錯覺,即這些字段在某種程度上是接口的一部分-可能會更多地鍵入內容,但是代碼要干凈得多。

暫無
暫無

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

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