NuGetから入手可能なDeepClonerを使用することをお勧めします。私はこのライブラリがちょうどあなたが必要とするものを実装していると思うと拡張メソッドとして。オープンソースであり、GitHubでホストされているので、機能を追加したい場合や、機能の仕組みを知りたい場合は、コードをチェックすることができます。
プロジェクトサイトから:
また、クローニングのためのオブジェクト・タイプを指定する必要はありません。オブジェクトをintefaceまたは抽象オブジェクトとしてキャストすることができます。抽象ArrayまたはIEnumerableとしてintの配列を複製できます。ヌルをエラーなく複製することもできます。
私はそれがどのように動作するかを示すために、このサンプルを作った:
インタフェースと、このインタフェースを実装するクラス:
interface IPluginInterface { }
class Foo:IPluginInterface
{
public int SomeInt { get; set; }
public string SomeString { get; set; }
public Foo()
{
SomeInt = 42;
SomeString = "SomeString";
}
public override string ToString() => $"SomeInt: {SomeInt}. SomeString: {SomeString}";
}
その後Force.DeepClonerを使用して、メインの追加に。と...
static void Main(string[] args)
{
IPluginInterface foo = new Foo();
IPluginInterface fooWithActivator = (IPluginInterface) Activator.CreateInstance(typeof(Foo));
Console.WriteLine(foo);
var cloneOfFoo = foo.DeepClone();
var cloneOfFooWithActivator = fooWithActivator.DeepClone();
Console.WriteLine(cloneOfFoo);
Console.WriteLine(cloneOfFoo == foo);
Console.WriteLine(cloneOfFoo.GetType());
Console.WriteLine(cloneOfFooWithActivator);
Console.WriteLine(cloneOfFooWithActivator == foo);
Console.WriteLine(cloneOfFooWithActivator.GetType());
Console.ReadLine();
}
そして出力:

EDIT >>>>パフォーマンスについてのあなたの懸念に基づいて、私はいくつかのテストを行い、また、達成するための別の、より良い方法を見つけるしていますあなたが欲しいもの。
良い方法アプローチは反射、参加者およびジョンスキートの混合物を使用してMemberwiseCloneメソッドを呼び出すことを含みます。アイデアは、methodinfoインスタンスをデリゲートに変換することです。詳細は、Jon Skeet氏の投稿thisにあります。ここで
は)(メインです:
static void Main(string[] args)
{
const int howManyTimes = 10000000;
IPluginInterface foo = new Foo(true);
foo.ShallowCloneWithDeepClonerLibrary(howManyTimes);
foo.ShallowCloneWithReflection(howManyTimes);
((Foo)foo).ShallowCloneWithMemberWiseClone(howManyTimes);
foo.ShallowCloneWithDelegatesAndReflection(howManyTimes);
Console.ReadLine();
}
あなたは私たちが浅いクローニングのための4つのアプローチテストしている気付いているよう:直接MemberWiseCloneを公開
- DeepClonerライブラリ
- を。 (お使いの場合には適していません)METHODINFOは(拡張メソッドです)。これは、すべての4つのメソッドのコードであるデリゲート
を使用してMemberwiseClone
あるMethodInfo.Invokeを使用して
: public static void ShallowCloneWithDeepClonerLibrary(this object obj, int times)
{
Console.WriteLine($"Performing {times.ToString("##,###")} cloning operations with DeepCloner's ShallowClone method:");
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < times - 1; i++) obj.ShallowClone();
var clone = obj.ShallowClone();
sw.Stop();
Console.WriteLine($"Total milliseconds elapsed: {sw.ElapsedMilliseconds}");
Console.WriteLine($"Are both the same: {obj == clone}");
Console.WriteLine($"Cloned object: {Environment.NewLine}{clone}{Environment.NewLine}");
}
public static void ShallowCloneWithMemberWiseClone(this Foo obj, int times)
{
Console.WriteLine($"Performing {times.ToString("##,###")} cloning operations wiht MemberwiseClone:");
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < times - 1; i++) obj.Clone();
var clone = obj.Clone();
sw.Stop();
Console.WriteLine($"Total milliseconds: {sw.ElapsedMilliseconds}");
Console.WriteLine($"Are both the same: {obj == clone}");
Console.WriteLine($"Cloned object: {Environment.NewLine}{clone}{Environment.NewLine}");
}
public static void ShallowCloneWithDelegatesAndReflection(this object obj, int times)
{
Console.WriteLine(
$"Performing {times.ToString("##,###")} cloning operations by encapsulating MemberwiseClone method info in a delegate:");
var sw = new Stopwatch();
sw.Start();
var type = obj.GetType();
var clone = Activator.CreateInstance(type);
var memberWiseClone = type.GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic);
var memberWiseCloneDelegate =
(Func<object, object>)Delegate.CreateDelegate(typeof(Func<object, object>), memberWiseClone);
for (var i = 0; i < times; i++) clone = memberWiseCloneDelegate(obj);
sw.Stop();
Console.WriteLine($"Total milliseconds: {sw.ElapsedMilliseconds}");
Console.WriteLine($"Are both the same: {obj == clone}");
Console.WriteLine($"Cloned object: {Environment.NewLine}{clone}{Environment.NewLine}");
}
public static void ShallowCloneWithReflection(this object obj, int times)
{
Console.WriteLine($"Performing {times.ToString("##,###")} cloning operations manually with reflection and MemberwiseClone:");
var sw = new Stopwatch();
sw.Start();
var type = obj.GetType();
var memberWiseClone = type.GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic);
var clone = Activator.CreateInstance(type);
for (var i = 0; i < times - 1; i++)
clone = memberWiseClone.Invoke(obj, null);
sw.Stop();
Console.WriteLine($"Total milliseconds: {sw.ElapsedMilliseconds}{Environment.NewLine}");
Console.WriteLine($"Are both the same: {obj == clone}");
Console.WriteLine($"Cloned object: {Environment.NewLine}{clone}{Environment.NewLine}");
}
そして、それぞれの結果で1000万回のクローニング操作を行うミリ秒単位の結果:
- ディpCloner:
- MemberwiseClone直接:MethodInfo.Invokeと
- MemberwiseClone:代理人を通じて
- MemberwiseClone:
だから、我々は勝者を持っています!残念ながら、クラス内のMemberwiseCloneを公開することを意味するため、勝者はあなたのケースには適していません。しかし...私たちはすごい2位!ここで
が出力されます:あなたは* *それが複製可能であることを期待場合

、そして 'ICloneable'は*合理的*要件が以降渡すようです。一般的なケースでは、未知のオブジェクトの複製は非常に扱いにくいものです。 * 'GetType() 'で' FormatterServices.GetUninitializedObject'を介してコンストラクタをスキップし、 'private'や' readonly'でも強制的にインスタンスフィールドを設定することができます。)しかし、それは醜いです –
@MarcGravell合理化のために、私はプラグイン開発者にクローニングメソッドを作成する責任を避けたかったのです。しかし、それ以外の方法がない場合は最後の手段です – Wobbles
なぜ、クローンを作成する必要がありますか?クローンはどのような目的を果たすのでしょうか? –