我所拥有的是一组类,它们都实现了相同的接口,但在引擎盖下可能会有很大差异.我希望有一个配置文件控制在启动程序时哪些类进入集合,采取看起来像这样的东西:
把它变成:
blah = new class1(); blah.prop1="foo"; blah.prop2="bar";
以非常通用的方式.我不知道该怎么做的是prop1
将配置文件中的字符串转换为代码中的实际属性访问器.在C#中是否有任何元编程工具允许这样做?
将类序列化到/从xml可能更容易,然后您可以简单地将XmlReader(正在读取您的配置文件)传递给反序列化器,它将为您完成剩下的工作.
这是关于序列化的一篇非常好的文章
有一件事我想补充一点,即使反射很强大,它也需要你知道关于类型的一些东西,比如参数等.
序列化为XML不需要任何这些,并且您可以通过确保将完全限定的类型名称写入XML文件来保持类型安全,因此会自动加载相同的类型.
反射允许你这样做.您还可以查看XML序列化.
Type type = blah.GetType(); PropertyInfo prop = type.GetProperty("prop1"); prop.SetValue(blah, "foo", null);
我还建议其他人已经提到的Xml序列化.这是一个我一起展示的样本.属性用于将Xml中的名称连接到数据结构中的实际属性名称和类型.属性还列出了可以进入Things
集合的所有允许类型.此集合中的所有内容都必须具有公共基类.你说你已经有了一个通用的接口 - 但是你可能不得不把它改成一个抽象的基类,因为这个代码示例在Thing
接口时没有立即起作用.
using System; using System.Collections.Generic; using System.Text; using System.Xml.Serialization; using System.IO; namespace ConsoleApplication1 { class Program { static void Main() { string xml = "" + "" + " "; StringReader sr = new StringReader(xml); XmlSerializer xs = new XmlSerializer(typeof(ThingCollection)); ThingCollection tc = (ThingCollection)xs.Deserialize(sr); foreach (Thing t in tc.Things) { Console.WriteLine(t.ToString()); } } } public abstract class Thing { } [XmlType(TypeName="class1")] public class SomeThing : Thing { private string pn1; private string pn2; public SomeThing() { } [XmlAttribute("prop1")] public string PropertyNumber1 { get { return pn1; } set { pn1 = value; } } [XmlAttribute("prop2")] public string AnotherProperty { get { return pn2; } set { pn2 = value; } } } [XmlType(TypeName="class2")] public class SomeThingElse : SomeThing { private int answer; public SomeThingElse() { } [XmlAttribute("prop3")] public int TheAnswer { get { return answer; } set { answer =value; } } } [XmlType(TypeName = "config")] public class ThingCollection { private List" + " " + "" + " " + " things; public ThingCollection() { Things = new List (); } [XmlArray("stuff")] [XmlArrayItem(typeof(SomeThing))] [XmlArrayItem(typeof(SomeThingElse))] public List Things { get { return things; } set { things = value; } } } }
您正在寻找反射或XML序列化.
使用反射,您可以使用类似的东西查找类型
public IYourInterface GetClass(string className) { foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) { foreach (Type type in asm.GetTypes()) { if (type.Name == className) return Activator.CreateInstance(type) as IYourInterface; } } return null; }
请注意,这将遍历所有程序集.您可能希望将其减少为仅包含当前正在执行的程序集.
要分配属性值,还可以使用反射.有点像
IYourInterface o = GetClass("class1"); o.GetType().GetProperty("prop1").SetValue(o, "foo", null);
虽然反射可能是最灵活的解决方案,但您还应该看看XML序列化,以便自己跳过繁重的工作.