繁体   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