我可以用C#制作一个动态界面吗?
我已经创建了一个自定义类(DynamicItem),它继承了DynamicObject类,这对于dynamic关键字非常有用。DynamicItem还实现和接口,因为我知道某些属性总是会出现,对此的测试如下:我可以用C#制作一个动态界面吗?,c#,c#-4.0,C#,C# 4.0,我已经创建了一个自定义类(DynamicItem),它继承了DynamicObject类,这对于dynamic关键字非常有用。DynamicItem还实现和接口,因为我知道某些属性总是会出现,对此的测试如下: [Test] public void InterfaceTest() { //Assign Item item = _db.GetItem(TargetPath); dynamic d = new
[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);
}
“Title”属性未在接口上定义,而是动态调用的。“路径”属性在接口上定义
这个测试通过了,一切都按照您的预期进行。让我恼火的是,我不得不从动态转换到界面。我想做的就是使用界面:
[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所评论的,实际上需要动态对象的情况非常罕见。在大多数情况下,您只需使用
字典
(或类似的工具),就可以获得一种更安全的方法,而不会让其他人感到困惑。在多年的编程中,我只需要使用动态
关键字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 ) );
}
}
}
公共接口IMyDynamicItem
{
字符串SomeItemName{get;set;}
对象此[int nFieldIndex]{get;set;}
对象此[string sFieldName]{get;set;}
IList字段名{get;}
}
公共类MyDynamicItem:IMyDynamicItem
{
专用词典m_of ields=
新字典();
公共字符串SomeItemName{get;set;}
公共对象此[int nFieldIndex]
{
得到
{
字符串sFieldName=字段名[nFieldIndex];
返回(字段的m_[sFieldName]);
}
设置
{
字符串sFieldName=字段名[nFieldIndex];
m_of ields[sFieldName]=值;
}
}
公共对象此[string sFieldName]
{
得到
{
返回(字段的m_[sFieldName]);
}
设置
{
m_of ields[sFieldName]=值;
}
}
公共IList字段名
{
得到
{
返回(新列表(m_of ields.Keys));
}
}
}
我不确定这是否是最好的方法,但这会让您大致了解您试图实现的目标,但这并不理想-真正的接口成员可以通过点表示法(即,oItem.SomeItemName
)访问,但动态成员只能通过索引器表示法(oItem[2]
或oItem[“SomeField”]
)
可以将接口成员添加到内部字典中,这样就可以通过索引器符号查找所有成员——我个人认为这种方法很糟糕。在这种情况下,,我可能只是将动态字段分离到一个真正的字典中,而不是试图保持那些字段在某种程度上是接口的一部分的假象——可能需要更多的键入,但代码要干净得多。使用dynamic关键字来删除C#的类型安全性是非常罕见的情况。为什么要使用它?接口是组件提前知道的方法和属性的预定义契约。一个动态对象与之正好相反。我正在与一个具有未知字段的CMS进行集成。如果能够在界面上拥有已知项属性,然后允许用户通过动态类型访问其自定义字段,那就太好了。OP似乎在寻找某种“半动态”机制,正如您和其他人所建议的,最好使用
字典
属性来保存额外的未知属性。也许可以给出一个包含两个定义良好的属性和一个字典的类的超薄示例,以及如何使用它的示例?@ean5533请记住,OP将无法执行他在代码段中尝试的操作:我可以创建一个带有一些静态成员和类似字典的查找方法的接口,但是OP将无法使用点符号访问字典部分。同意。我看到了两个接近OP所需的选项:1)myObject.KnownProp
和myObject.UnknownProps[“key1”]
。不理想。2) 编写一个索引器,这样您就可以执行myObject.KnownProp
和myObject[“key1”]
。更好,但仍然不理想。@ean5533我添加了一个代码示例。谢谢你的建议。