15

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

只要我只Foo<T>用实现的类进行实例化,这将起作用IPCLCloneable,但它不适用于例如来自实现的核心库的类型ICloneable,例如Array

var x = new Foo<int[]>();  // Compilation error in PCL library

(为了完整起见,应该指出,该ICloneable接口没有在可移植子集核心库中显式实现,因为它不存在,但该object Clone()方法确实存在于可移植子集Array类中,因此对于数组实现,例如int[].)

我还有什么其他选择?

4

4 回答 4

13

ICloneable是我们在设计 API 时犯错误的教科书示例。它是做深拷贝还是浅拷贝是未定义的,框架设计指南现在建议不要使用它

也就是说,如果您无论如何都需要使用它,您可以通过在 PCL 中定义接口(具有完全相同的名称)来从 PCL 执行此操作,并且当您在确实具有 ICloneable 的平台上运行时,将程序集替换为ICloneable 定义与一个具有向前“真实”版本的类型的定义。请在此处查看我的答案以了解更多信息:有什么方法可以在可移植类库项目上实现 IValidatableObject 吗?

于 2013-12-04T21:43:15.883 回答
4

我不知道这是否可以接受:

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();
}
于 2013-12-04T13:43:08.983 回答
3

.NET 比较器基础结构也有类似的问题。您有时想要对未实现的对象进行排序,IComparable但您可以在外部指定IComparer<T>排序算法。您可以在这里做类似的事情:创建一个ICloneProvider<T>支持克隆给定类型对象的接口。您必须确保所有需要克隆某些东西的代码都有该接口的合适实例可用。

于 2013-12-04T13:47:23.123 回答
1

从 .NET Standard 2.0 版本开始,该ICloneable接口又回来了,应该得到所有平台的支持:

https://docs.microsoft.com/en-us/dotnet/api/system.icloneable?view=netstandard-2.0

于 2017-08-28T16:09:06.097 回答