2011-03-14 16 views
2

私はdynamicのようなものについて話しています。 Thisは私の質問に答えなかったので、この質問。実行時にプロパティを追加できるクラスが必要です。タイプobjectから継承する必要があります。C#動的クラス

DynamicObjectから継承していますが、実行時にプロパティを追加する方法は記載されていません。私のために、この上にいくつかの光を流すことができますpls?

私はこのようなクラスがあります:私は、実行時にこのクラスに別のクラスからのすべてのプロパティを追加したい

public class SomeModel : DynamicObject { 
     public string SomeMandatoryProperty {get; set;} 
} 

を。だから例えば。

SomeModel m = new SomeModel(); 
m = someOtherClass; 
string hi = m.otherClassProp; //Property from other class is added. 
string mandatory = m.SomeMandatoryProperty; //From the mandatory property set previously. 
+0

あなたの前の質問に対する答えは、あなたが得られた最高のものです。なぜあなたはそれが気に入らなかったのですか? – Jon

+0

T4テンプレートを使用してソースコードを生成します。彼は特に、彼が「ダイナミック」のようなことについて話しているわけではないと言いました。私は「ダイナミック」のようなものを求めています。 –

答えて

1

必要に応じて、あなたが動的にプロパティを追加することができますようExpandoObjectを使用したいと思います。ただし、別のオブジェクトの値をインスタンスに簡単に取り込む方法はありません。リフレクションを使用して手動で追加する必要があります。

内部にアクセスしながらプロパティを追加できるラッパーオブジェクトを作成しますか? 2つの異なるオブジェクトインスタンス間で2つの値のコピーを管理する必要がないように考えることができます。私はあなたがこれを行う方法を示すために文字列オブジェクトをラップするテストクラスを作成しました(ExpandoObjectの仕組みと同様)。それはあなたのタイプのためにこれを行う方法についてのアイデアを与える必要があります。

class DynamicString : DynamicObject 
{ 
    static readonly Type strType = typeof(string); 
    private string instance; 
    private Dictionary<string, object> dynProperties; 
    public DynamicString(string instance) 
    { 
     this.instance = instance; 
     dynProperties = new Dictionary<string, object>(); 
    } 
    public string GetPrefixString(string prefix) 
    { 
     return String.Concat(prefix, instance); 
    } 
    public string GetSuffixString(string suffix) 
    { 
     return String.Concat(instance, suffix); 
    } 
    public override string ToString() 
    { 
     return instance; 
    } 
    public override bool TryConvert(ConvertBinder binder, out object result) 
    { 
     if (binder.Type != typeof(string)) 
      return base.TryConvert(binder, out result); 
     result = instance; 
     return true; 
    } 
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
    { 
     var method = strType.GetMethod(binder.Name, args.Select(a => a.GetType()).ToArray()); 
     if (method == null) 
     { 
      result = null; 
      return false; 
     } 
     result = method.Invoke(instance, args); 
     return true; 
    } 
    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     var members = strType.GetMember(binder.Name); 
     if (members.Length > 0) 
     { 
      var member = members.Single(); 
      switch (member.MemberType) 
      { 
      case MemberTypes.Property: 
       result = ((PropertyInfo)member).GetValue(instance, null); 
       return true; 
       break; 
      case MemberTypes.Field: 
       result = ((FieldInfo)member).GetValue(instance); 
       return true; 
       break; 
      } 
     } 
     return dynProperties.TryGetValue(binder.Name, out result); 
    } 
    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     var ret = base.TrySetMember(binder, value); 
     if (ret) return true; 
     dynProperties[binder.Name] = value; 
     return true; 
    } 
} 

あなたが夢中になりたい場合は、独自のメタオブジェクトを定義してバインディングを処理できます。さまざまなタイプの再利用可能なメタオブジェクトになり、コードを大幅に単純化することができます。私はこれとしばらく遊んでいて、今までこれを持っています。まだ動的にプロパティを追加することはできません。私はこれ以上はこれに取り組んでいませんが、ここでは参考にしておきます。

class DynamicString : DynamicObject 
{ 
    class DynamicStringMetaObject : DynamicMetaObject 
    { 
     public DynamicStringMetaObject(Expression parameter, object value) 
      : base(parameter, BindingRestrictions.Empty, value) 
     { 
     } 
     public override DynamicMetaObject BindConvert(ConvertBinder binder) 
     { 
      if (binder.Type == typeof(string)) 
      { 
       var valueType = Value.GetType(); 
       return new DynamicMetaObject(
        Expression.MakeMemberAccess(
         Expression.Convert(Expression, valueType), 
         valueType.GetProperty("Instance")), 
        BindingRestrictions.GetTypeRestriction(Expression, valueType)); 
      } 
      return base.BindConvert(binder); 
     } 
     public override DynamicMetaObject BindGetMember(GetMemberBinder binder) 
     { 
      System.Diagnostics.Trace.WriteLine(String.Format("BindGetMember: {0}", binder.Name)); 
      var valueType = Value.GetType(); 
      var self = Expression.Convert(Expression, valueType); 
      var valueMembers = valueType.GetMember(binder.Name); 
      if (valueMembers.Length > 0) 
      { 
       return BindGetMember(self, valueMembers.Single()); 
      } 
      var members = typeof(string).GetMember(binder.Name); 
      if (members.Length > 0) 
      { 
       var instance = 
        Expression.MakeMemberAccess(
         self, 
         valueType.GetProperty("Instance")); 
       return BindGetMember(instance, members.Single()); 
      } 
      return base.BindGetMember(binder); 
     } 
     private DynamicMetaObject BindGetMember(Expression instance, MemberInfo member) 
     { 
      return new DynamicMetaObject(
       Expression.Convert(
        Expression.MakeMemberAccess(instance, member), 
        typeof(object)), 
       BindingRestrictions.GetTypeRestriction(Expression, Value.GetType()) 
      ); 
     } 
    } 
    public string Instance { get; private set; } 
    public DynamicString(string instance) 
    { 
     Instance = instance; 
    } 
    public override DynamicMetaObject GetMetaObject(Expression parameter) 
    { 
     return new DynamicStringMetaObject(parameter, this); 
    } 
    public override string ToString() 
    { 
     return Instance; 
    } 
    public string GetPrefixString(string prefix) 
    { 
     return String.Concat(prefix, Instance); 
    } 
    public string GetSuffixString(string suffix) 
    { 
     return String.Concat(Instance, suffix); 
    } 
} 
+0

私は何千ものオブジェクトを変換している場合、これが非常に遅いと仮定しています。右? –

+0

@Lol:ラップされたオブジェクトを使用している場合、値をコピーするのではなくラップされたオブジェクトにすべてを委譲するので、ExpandoObjectを使用するよりもはるかに高速です。その後、両方のアプローチが同様に動作するので、両方とも同様に動作するはずです。そして、はい、それは、反映に伴うダイナミックタイプの使用によって、比較的遅くなります。この時点で、値をコピーする際やリフレクションを使用する際に、スピードで支払うかどうかを決定する必要があります。何千ものオブジェクトで、私は反射に固執します。 –

2

代わりにExpandoObjectを使用することができます。

dynamic employee, manager; 

    employee = new ExpandoObject(); 
    employee.Name = "John Smith"; 
    employee.Age = 33; 

    manager = new ExpandoObject(); 
    manager.Name = "Allison Brown"; 
    manager.Age = 42; 
    manager.TeamSize = 10; 
3

私はあなたがExpandoObjectを探していると思う:ExpandoObjectは、メンバーが追加されたり、実行時に削除され、あなたがMSDNドキュメントからXMLなど

に変換したい場合は非常に素晴らしいサポートを持っていることができ

ExpandoObjectクラスを使用すると、実行時に インスタンスのメンバーを追加および削除し、 を設定し、これらのメンバーの値を取得することができます。この クラスは動的バインディングをサポートしています。 は、 sampleObject.GetAttribute( "sampleMember")のようなより複雑な構文の の代わりに、標準構文の (sampleObject.sampleMember)を使用できるようにします。

dynamic manager; 

manager = new ExpandoObject(); 
manager.Name = "Allison Brown"; 
manager.Age = 42; 
manager.TeamSize = 10; 
+0

これに別のクラスのプロパティをマージする方法はありますか? –

+0

あなたはそれを行うためにリフレクションを使うことができますが、他のより簡単な方法はわかりません。 – BrokenGlass