13

私が持っているのは、すべて同じインターフェースを実装するクラスのコレクションですが、内部ではかなり大きく異なる可能性があります。プログラムの起動時にどのクラスがコレクションに入るかを構成ファイルで制御したいのですが、次のようになります。

<class1 prop1="foo" prop2="bar"/>

そしてそれを次のように変えます:

blah = new class1();
blah.prop1="foo";
blah.prop2="bar";

非常に一般的な方法で。どうすればよいかわからないのはprop1、構成ファイル内の文字列を取得し、それをコード内の実際のプロパティ アクセサーに変換することです。それを可能にするメタプログラミング機能は C# にありますか?

4

8 に答える 8

9

クラスをxmlとの間でシリアル化する方が簡単な場合があります。その後、XmlReader(構成ファイルを読み取っている)をデシリアライザーに渡すだけで、残りの作業が自動的に行われます。

これはシリアル化に関するかなり良い記事です

編集

私が付け加えたいことの1つは、リフレクションは強力ですが、パラメーターなど、タイプに関するいくつかのことを知っている必要があります。

XMLへのシリアル化にはそれは必要ありません。また、完全修飾型名をXMLファイルに書き込むことで型の安全性を確保できるため、同じ型が自動的にロードされます。

于 2008-08-27T20:47:43.293 に答える
9

リフレクションはあなたがそれをすることを可能にします。XMLシリアル化も確認することをお勧めします。

Type type = blah.GetType();
PropertyInfo prop = type.GetProperty("prop1");
prop.SetValue(blah, "foo", null);
于 2008-08-27T20:51:13.270 に答える
8

他の人がすでに述べたように、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 =
                "<?xml version=\"1.0\"?>" + 
                "<config>" +
                "<stuff>" + 
                "  <class1 prop1=\"foo\" prop2=\"bar\"></class1>" +
                "  <class2 prop1=\"FOO\" prop2=\"BAR\" prop3=\"42\"></class2>" +
                "</stuff>" +
                "</config>";
            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<Thing> things;

        public ThingCollection()
        {
            Things = new List<Thing>();
        }

        [XmlArray("stuff")]
        [XmlArrayItem(typeof(SomeThing))]
        [XmlArrayItem(typeof(SomeThingElse))]
        public List<Thing> Things
        {
            get { return things; }
            set { things = value; }
        }
    }
}
于 2008-08-28T01:43:22.007 に答える
6

リフレクションまたは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シリアル化も検討する必要があります。

于 2008-08-27T20:50:51.647 に答える
3

たくさんのメタプログラミング機能。

Type具体的には、これらのクラスを保持するアセンブリへの参照を取得し、その名前からクラスのを簡単に取得できます。Assembly.GetTypeメソッド(文字列)を参照してください。

そこから、Activatorまたはそれ自体のコンストラクターを使用してクラスをインスタンス化できますTypeActivator.CreateInstanceメソッドを参照してください。

インスタンスを作成したら、Typeオブジェクトを再度使用してプロパティを設定できます。PropertyInfo.SetValueメソッドに沿ったType.GetPropertyメソッドおよび/またはType.GetFieldメソッドを参照してください。

于 2008-08-27T20:48:32.900 に答える
1

ここでダイナミクスを利用できると思います。ExpandoObjectを作成します。これは、xmlconfigからプロパティを設定するためのディクショナリとして使用できます。

于 2012-09-21T11:33:26.263 に答える
1

最近、非常に似たようなことをしました。抽象ファクトリを使用しました。実際、ここで基本的な概念を見ることができます。

抽象ファクトリデザインパターン

于 2008-08-28T01:53:51.543 に答える
0

反射はあなたが望むものです。リフレクション+TypeConverter。説明する時間はあまりありませんが、グーグルで検索すれば、順調に進んでいるはずです。または、xmlシリアライザーを使用することもできますが、その場合はフォーマットに準拠する必要がありますが、うまく機能します。

于 2008-08-27T20:47:19.363 に答える