如何解决将.NET库移植到PCL时缺少ICloneable接口的问题



我正在将现有的.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

相关内容

  • 没有找到相关文章

最新更新