Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to workaround missing ICloneable interface when porting .NET library to PCL?

I am porting an existing .NET class library to a Portable Class Library. The .NET library makes extensive use of the ICloneable interface, which is not included in the portable subset.

Typically, I am faced with class definitions like this in the .NET class library:

public class Foo<T> where T : ICloneable
{
    public void Bar(T item) {
        var x = item.Clone();
        ...
    }
}

What can I do to successfully port this code to a Portable Class Library? Do I have to rewrite the Clone method invocations, or is there a less intrusive workaround?

I cannot simply remove the generic type constraint where T : ICloneable because then the Bar method will not compile.

I could write up a replacement interface to use instead of ICloneable in the ported code:

public interface IPCLCloneable {
    object Clone();
}

This would work as long as I only instantiate Foo<T> with classes that implement IPCLCloneable, but it will not work for example with types from the core libraries that implement ICloneable, such as Array:

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

(For completeness, it should be pointed out that the ICloneable interface is not explicitly implemented in the portable subset core libraries since it does not exist, but the object Clone() method does exist in the portable subset Array class, and consequentially for array implementations such as int[].)

What other options do I have?

like image 889
Anders Gustafsson Avatar asked Dec 04 '13 13:12

Anders Gustafsson


2 Answers

ICloneable is kind of the textbook example of where we made a mistake when designing an API. Whether it does a deep or shallow copy is undefined, and the Framework Design Guidelines now recommend not using it.

That said, if you need to use it anyway, you can probably do so from PCLs by defining the interface (with the exact same name) in a PCL, and when you are running on a platform that does have ICloneable, replacing the assembly with the ICloneable definition with one which has a type forward to the "real" version. See my answer here for a bit more on this: Is there any way I can implement IValidatableObject on Portable Class Library Project?

like image 63
Daniel Plaisted Avatar answered Oct 27 '22 10:10

Daniel Plaisted


I don't know if this is acceptable:

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();
}
like image 32
Jeppe Stig Nielsen Avatar answered Oct 27 '22 10:10

Jeppe Stig Nielsen