不确定我的白话是否正确所以请耐心等待。
我在插件中使用了一个公共接口,实现此接口的类我希望可以克隆,同时保持其声明类型和其中的所有属性。
我知道ICloneable
并且我可以简单地将其实现到我的界面中,但我不想将实现接口的要求传递给插件开发人员并希望自己控制它。
另外值得注意的是,它需要重量轻,不需要很深。除了实现我的插件接口之外,我在设计时也不知道任何声明的类型,因此我需要将其转换为“未知”源类型。
public interface ImyInterface
{
int commonProp {get;set;}
}
// This class and the properties therein are not known at design time
public myObj : ImyInterface
{
int commonProp {get;set;}
int uncommonProp {get;set;}
}
然后我需要从我的应用程序中调用类似的东西:
// This is how I generally "activate my plugins"
ImyInterface obj = (ImyInterface)Activator.CreateInstance(type);
// Then elsewhere I need to clone its current state.
var ClonedObj = obj.clone();
我试过this,但它要求我在设计时知道类型。
答案 0 :(得分:2)
我建议您使用NuGet提供的DeepCloner。我认为这个库实现了你所需要的和扩展方法。它也是开源的,并在GitHub中托管,因此如果您想添加更多功能或只是想知道它是如何工作的,您可以检查代码。
从项目现场:
此外,无需指定克隆的对象类型。对象可以转换为inteface或作为抽象对象,你可以将int数组克隆为抽象数组或IEnumerable,甚至可以克隆null而不会出现任何错误。
我制作了这个样本来展示它的工作原理:
实现此接口的接口和类:
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}";
}
然后在main中添加使用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();
}
输出:
编辑>>>>根据您对性能的担忧,我已经进行了一些测试,并找到了另一种更好的方法来实现您的目标。
更好的方法是使用 Reflection,Delegates和Jon Skeet 的混合方法调用 MemberwiseClone 方法。我们的想法是将methodinfo实例转换为委托,更多信息可以在Jon Skeet的this帖子中找到。
这是main():
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种方法的代码(扩展方法):
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}");
}
结果以毫秒为单位进行10,000,000次克隆操作:
所以,我们有一个胜利者!不幸的是,胜利者不适合你的情况,因为这意味着在课堂上暴露出MemberwiseClone。但是......我们有一个巨大的第二名!
这是输出: