2

かなり手の込んだ質問をするつもりですが、これもここでの考えのようなものですので、我慢してください...

シミュレーションアプリケーションのファクトリ実装を設計しようとしています。シミュレーションはさまざまな種類のエンティティで構成されます。つまり、どの点でも同種のシミュレーションではありません。その結果、非常に異なる具体的な実装が多数存在し、非常に一般的なプロパティのみがトップレベルで抽象化されます。

私ができるようにしたいのは、エンティティのパラメーターを表す一連の名前付き引数を使用してモデルのメソッドを呼び出して新しいシミュレーションエンティティを作成し、モデルにインバウンドによって記述されているオブジェクトのタイプを推測させることです。パラメータ(パラメータの名前と、場合によってはそれらが発生するシーケンスから)を選択し、適切な派生クラスのファクトリメソッドを呼び出します。

たとえば、モデルにパラメータのペア(Param1 = 5000、Param2 = "Bacon")を渡す場合、Param1とParam2の名前がクラス「Blob1」に「属している」と推測し、共有関数「」を呼び出します。名前付きパラメーターParam1:= 5000、Param2:= "Bacon"を持つgetBlob1"に対して、モデル(Param1 = 5000、Param3 = 50)を渡すと、Blob2に対して同様のファクトリメソッドが呼び出されます。これは、Param1とParam3がこの順序でBlob2に「属している」ためです。

私は解決すべきいくつかの問題を予見しています:

  • 文字列パラメータ名を使用して使用可能な型について検討できるかどうか、および可能であればこれを行う方法
  • 引数リストの組み合わせプロパティから適切なコンストラクター推論を行うための適切な方法があるかどうか、またはそれを「手作業で」行うために何かをしなければならないかどうか。
  • 可能であれば、モデルクラスがキーと値のコレクションとしてではなく、パラメーターとしてパラメーターを受け入れることができるようにしたいと思います。これにより、モデルは、明示的にコーディングしなくても、実行時に多数のパラメーター化されたメソッドを公開する必要があります。おそらく、関連する名前空間で使用可能なすべてのファクトリメソッドに1つです。

私が本当に求めているのは、基本的に可能かどうかではなく、そのようなシステムをどのように実装するかということです。私には、自分で道を見つけることができる.NETリフレクションの先見性や経験がありません。うまくいけば、これは有益な議論を証明するでしょう。

更新

さて、私は基本的に、単純なケース、おもちゃのモデルを実装することに亀裂がありました。したがって、コアロジックは次のとおりです。

Dim members() As Reflection.MethodInfo = Me.GetType.GetMethods()
    Dim params_enum As IEnumerator(Of String) = params.Keys.GetEnumerator

    While params_enum.MoveNext
        members = Array.FindAll(members, _
                                Function(m As Reflection.MethodInfo) Array.Exists(CType(m, Reflection.MethodInfo).GetParameters(), _
                                                                                  Function(mm As Reflection.ParameterInfo) mm.Name = params_enum.Current))
        If members.Count = 0 Then Return False
    End While
    Try
        CType(members(0), Reflection.MethodInfo).Invoke(Me, params.Values.ToArray())
        Return True
    Catch ex As Exception
        Return False
    End Try

This just picks a method on the current instance and executes it. I'd like to extend that to a subset of all the types in the assembly. I'd also like to do this, if possible, by letting those types decide what their parametrised initialisation requirements are at runtime by examining their own properties, i.e. each property marked with 'ParametrisedInitAttribute' corresponds to exactly one named argument in the factory method. This would require that I have these types expose a method with N arguments at runtime. Is there a way to construct a method with an arbitrary signature and add it to the class implementation at runtime, or a similar way of doing this sort of thing?

4

2 に答える 2

1

This seems like a good place to use the new dynamic features of .NET 4 - a DynamicObject can override TryInvokeMember to examine the name and arguments a method is invoked with; you can use that to build a dictionary of factory methods that will be called dynamically based on the passed arguments. Here's an example I just cooked up:

The dynamic factory class:

class DynaTest : DynamicObject
{
    Dictionary<string, Func<object[], object>> builders;

    public DynaTest()
    {
        builders = new Dictionary<string, Func<object[], object>>();
        builders.Add("fur,fangs", args => 
                     new Dog((string)args[0], (int)args[1]));
        builders.Add("fur,claws", args => 
                     new Cat((string)args[0], (string)args[1]));
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, 
                                         object[] args, out object result)
    {
        string key = String.Join(",", binder.CallInfo.ArgumentNames.ToArray());
        Func<object[], object> builder;
        if (builders.TryGetValue(key, out builder))
        {
            result = builder(args);
            return true;
        }
        else
        {
            result = null;
            return false;
        }
    }
}

The classes we want to build:

class Dog
{
    string _fur;
    int _fangs;
    public Dog(string fur, int fangs)
    {
        _fur = fur;
        _fangs = fangs;
    }
    public void Bark() 
    { 
        Console.WriteLine("Woof! I have " + _fur + " fur and " 
                          + _fangs + " fangs."); 
    }
}

class Cat
{
    string _fur;
    string _claws;
    public Cat(string fur, string claws)
    {
        _fur = fur;
        _claws = claws;
    }
    public void Meow() 
    { 
        Console.WriteLine("Meow! I have " + _fur + " fur and "
                          + _claws + " claws."); 
    }
}

Test code:

static void Main(string[] args)
{
    dynamic dyn = new DynaTest();
    Dog d = dyn.Build(fur: "rough", fangs: 4);
    d.Bark();
    Cat c = dyn.Build(fur: "shiny", claws: "sharp");
    c.Meow();
}

Output:

Woof! I have rough fur and 4 fangs.
Meow! I have shiny fur and sharp claws.

Note: this is my own first time playing with dynamic, so there might be issues with this I'm unaware of.

于 2010-06-13T19:56:17.167 に答える
0

What you want to do is perfectly possible with Reflection and can be done more or less straight forward as you described it:

  • Iterate over all available types. You have different options how to do that. You can choose types by a common subclass, by a certain interface, mark them with an attribute, ... It depends on your concrete implementation what's best for you. There are also frameworks which help to do that, but again you have to check your concrete requirements.

  • For all these types you can retrieve the "factory", which might be the constructor for example.

  • For all these factories you can query the required parameters with their types and names.

  • Now you have to define some ordering rules for these factories and if you want to construct an object, you just go through the list and search for the first matching factory.

Implementation should be quite simple, but perhaps a bit boring. For each step there are different options to fine tune the solution for your requirements.

于 2010-06-12T11:10:55.617 に答える