我正在将现有的.NET类库移植到可移植类库。.NET库广泛使用ICloneable接口,该接口不包含在可移植子集中。
通常,我在.NET类库中会遇到这样的类定义:
public class Foo<T> where T : ICloneable
{
public void Bar(T item) {
var x = item.Clone();
...
}
}
如何将此代码成功移植到可移植类库?我是否必须重写Clone
方法调用,或者是否有侵入性较小的解决方法
我不能简单地删除泛型类型约束where T : ICloneable
,因为那样Bar
方法就不会编译。
我可以在移植的代码中写一个替换接口来代替ICloneable
:
public interface IPCLCloneable {
object Clone();
}
只要我只使用实现IPCLCloneable
的类实例化Foo<T>
,这就可以工作,但将不起作用,例如,对于实现ICloneable
的核心库中的类型,如Array:
var x = new Foo<int[]>(); // Compilation error in PCL library
(为了完整性,应该指出的是,ICloneable
接口没有在可移植子集核心库中明确实现,因为它不存在,但object Clone()
方法确实存在于可移植子集Array
类中,因此也存在于int[]
等阵列实现中。)
我还有什么其他选择?
ICloneable
是一个教科书式的例子,说明我们在设计API时犯了错误。无论是深度复制还是浅层复制都没有定义,框架设计指南现在建议不要使用它
也就是说,如果你无论如何都需要使用它,你可能可以通过在PCL中定义接口(具有完全相同的名称)来从PCL中使用它,当你在一个具有ICloneable的平台上运行时,用ICloneaable定义的程序集替换为一个具有转发到"真实"版本的类型的程序集。关于这方面的更多信息,请参阅我的回答:有什么方法可以在可移植类库项目上实现IValidatableObject吗?
我不知道这是否可以接受:
public class Foo<T>
{
// since we can't check T at compile-time anymore (no constraint), we do this
static Foo()
{
if (!typeof(IPclCloneable).IsAssignableFrom(typeof(T)) && !typeof(T).IsArray)
throw new ArgumentException("Type must have Clone method", "T");
}
public void Bar(T item)
{
var x = item.Clone();
...
}
}
public static class YourExtensions
{
public static object Clone(this object obj)
{
if (obj == null)
throw new ArgumentNullException("obj");
var objIPclCloneable = obj as IPclCloneable;
if (objIPclCloneable != null)
return objIPclCloneable.Clone();
var objArray = obj as Array;
if (objArray != null)
return objArray.Clone();
throw new ArgumentException("Type of 'this' must have Clone method", "obj");
}
}
public interface IPclCloneable
{
object Clone();
}
.NET比较器基础结构也有类似的问题。有时,您希望对不实现IComparable
的对象进行排序,但可以从外部为排序算法指定IComparer<T>
。您可以在这里做类似的事情:创建一个支持克隆给定类型对象的接口ICloneProvider<T>
。您必须确保所有需要克隆的代码都有一个合适的接口实例。
从.NET Standard 2.0版本开始,ICloneable
接口已经恢复,所有平台都应该支持:
https://learn.microsoft.com/en-us/dotnet/api/system.icloneable?view=netstandard-2.0