3

あるオブジェクトから別のオブジェクトにすべてのパブリック プロパティをコピーする機能を必要とするクラスの特定の階層があります。各クラスには、他のクラス とは異なる可能性が
ある特定のパブリック プロパティのセットがあります。

例:

class Base
{
  // Common properties/methods...
  public void Copy<T>(T data) where T : Base
  {
     // ...
  }
}

class D1 : Base
{
  public int ID
  {
    get;
    set;
  }
}

class D2 : Base
{
  public string Name
  {
    get;
    set;
  }
}

グーグルを通じて、これらの方法について読みました:

  • リフレクションの使用
  • IL コードの生成
  • シリアル化

それらはすべて、非常に複雑か非常に遅いか、場合によってはその両方です。
何か不足していますか?this生ポインタにアクセスする他の方法はありますか?

編集:
明確にします。
T は、呼び出しクラスの型です。たとえば、D1 によって呼び出された場合、T は常に D1 になります。
ジェネリックの理由は、T が何であるかを実際に知ることができないためです。
何か不足していますか?パラメータとして
使用する必要がありますか?Base data

4

5 に答える 5

6

欠落しているのは、Tがベースであると言っただけで、TがタイプD1およびD2の1つである可能性があることをコンパイラーに認識させていることです。その情報は実行時にのみ知られているので、どのようにしてプロパティが何であるかを知ることができ、オブジェクトを入力することさえできます。たとえあなた行くforeach (PropertyInfo in this.Properties)ことができたとしても、実行時にそれらのプロパティの名前を見つけることになるので、他にどのようにそれができるので、Reflectionと同じくらい遅くなりますか?(これリフレクションであり、構文がよりきれいです)。処理しているタイプがわかり、「実行時まで通知しない」と言われるまで、どのプロパティが一般的であるかを知ることはできません。そのため、答えは「実行時を確認する必要があります」、つまりリフレクションです。

次に、D1とD2の両方にSizeという名前のプロパティがあるからといって、それらが同じプロパティであるとは限りません(そのプロパティが共通の祖先に存在する場合を除く)。

例えば、

  • ArtilleryAmmo.ShellとPecanNut.Shell。
  • AcmeCorp.StaffおよびGandolfTheWizard.Staff
  • California.StateおよびMyBrokenEngine.State
  • LoudSpeaker.VolumeおよびMassiveCrater.Volume
  • Cave.BatsとBasketballGame.Bats

などなど。

于 2010-06-30T08:34:05.327 に答える
2

アーキテクチャの変更を使用してこれを回避し、「PropertyBag」を使用して各クラスのプロパティを保存できます。

PropertyBag は基本的に、Dictionary<string, object>データに名前を付けてバッグに追加できる場所です。不利な点は、すべてが にキャストされるobjectため、タイプ セーフではないことに加えて、多くのボックス化/ボックス化解除が行われることに加えて、コンパイル時に名前としての文字列がチェックされないため、タイプミスが常に脅威となります。

クラスでプロパティを定義するときは、クラスのプロパティバッグからアイテムを保存/取得します。

public int MyProperty
{
    get
    {
        return (int)_propertyBag["MyProperty"];
    }
    set
    {
        if(_propertyBag.Keys.Contains("MyProperty"))
        {
          _propertyBag["MyProperty"] = value;
        }
        else
        {
          _propertyBag.Add("MyProperty", value);
        }
    }
}

したがって、派生クラスのすべてのプロパティを集約するために、それらの「生の」PropertyBag を公開して、それを反復処理できます。

前に述べたように、PropertyBags はタイプ セーフではないため、同じプロパティ名でタイプが異なる 2 つのクラスが階層内にあると、問題が発生します。

編集: パフォーマンスに関心がある場合は、この複数の方法を実装し、さまざまな実装をパフォーマンス テストする必要があります。PropertyBag が実際にリフレクションを使用するよりも高速になるかどうかは正直わかりません。

于 2010-06-30T08:41:42.437 に答える
1

copy メソッドは、派生クラス D1、D2 に継承され、独自のプロパティを他の型との間でコピーする責任があると思います。

于 2010-06-30T08:41:47.680 に答える
1

クラスのCopyメソッドは、Baseクラスで定義されているプロパティにのみアクセスできますBase。これらのプロパティをコピーできます。

ただし、リフレクションなどを使用せずにサブクラスからプロパティをコピーすることはできません。IDただし、リフレクションを使用しても、プロパティを にコピーするなど、異なるサブクラス間のプロパティのマッピングに関する知識が必要ですName

そのため、(許可されている) サブクラス変換ごとに個別の実装を記述する必要があります。

public interface IBaseCopier<TFrom, TTo> where TFrom : Base, TTo : Base
{
  void Copy(TFrom from, TTo to);
}

public class D1ToD2Copier : IBaseCopier<D1, D2>
{
  public void Copy(D1 from, D2 to)
  {
    // Copy properties from the D1 instance to the D2 instance.
  }
}

ICopier<TFrom, TTo>ファクトリ クラスにすべての実装を登録できます。このクラスは、型引数に基づいてコピー機の実装を検索します。特定の型の組み合わせのコピー機がない場合、つまり変換がサポートされていない場合、ファクトリは例外をスローする必要があります。

public class CopierFactory
{
  public ICopier<TFrom, TTo> Create<TFrom, TTo>() where TFrom : Base, TTo : Base
  {
    // Look up the ICopier implementation for the given types.
  }
}

編集

MemberwiseCloneメソッドを使用して、オブジェクトのコピーを作成できます。

public class Base
{
  public static T Copy<T>(T data) where T : Base
  {
    return data.MemberwiseClone() as T;
  }
}

クローニングをさらに制御する必要がある場合は、ICloneable インターフェイスを実装できます。

注:D1インスタンスをインスタンスに複製することはできないことに注意してくださいD2。それは、羊のクローンを馬にするようなものです。

于 2010-06-30T08:59:22.273 に答える
0

私がすることは、次のような Base クラスの拡張メソッドを作成することです。

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int CopyTo<T>(this Base source, ref T dest)
        {
          // Use reflection to cycle public properties and if you find equally named ones, copy them.
        }
    }   
}

次に、オブジェクトなどでそれを呼び出すことができます:

  source.CopyTo<ClassType>(ref this);

私はテストしていないので、説明どおりに機能するかどうかはわかりません。私が取り組んだ大きなプロジェクトで、DataRows をエンティティにキャストするのと似たようなことをしました。

于 2010-06-30T08:46:34.093 に答える