通用克隆实例

本文关键字:实例 | 更新日期: 2023-09-27 18:22:16

我想要用CloneInstance方法创建接口,该方法返回该实例的Generic类。例如:

public interface ICloneableExtended<T> where T : this
{
    T CloneInstance();
}
public class Car : ICloneableExtended
{
   ...
   ...
   public Car CloneInstance()
   { .. }
}
Foo()
{
   Car car ...;
   var clonedCar = car.CloneInstance();
}

在类Car的定义中,我只需要使用ICloneableExtended,而不需要使用ICloneableExtended<T>。有办法做到这一点吗?

通用克隆实例

您可以接受将实现ICloneableExtended:的具体类的通用T参数

interface ICloneableExtended<T> {
    Clone();
}
class Car : ICloneableExtended<Car> {
    public Car Clone() {
        throw new NotImplementedException();
    }
}

您可以考虑使T参数协变(如果您希望将ICloneableExtended<Car>与许多具体类保持在一起-这将实现ICloneableExtended<T>):

interface ICloneableExtended<out T> {
    Clone();
}

请注意,您可能不需要通用的接口,您已经有了ICloneable(及其所有缺点和误用):

interface ICloneableExtended<out T> : ICloneable {
    Clone();
}

对于二进制可序列化类型,您甚至可以实现一个基本的、可重用的(但效率很低)基类:

interface ICloneableExtended<T> : ICloneable {
    T Clone();
}
abstract class Cloneable<T> : ICloneableExtended<T> {
    public virtual T Clone() {
        using (var ms = new MemoryStream()) {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, this);
            ms.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(ms);
        }
    }
    object ICloneable.Clone() {
        return Clone();
    }
}
sealed class Car : Cloneable<Car> { }

使用这种方法,每个具体类都必须实现ICloneableExtended<T>,但不能重载仅通过返回值进行区分的Clone()方法,因此最好显式实现ICloneableExtended<T>。一种不那么令人困惑的方法(对于谁实现这个接口以及谁将使用它)是提供扩展方法

static class Extensions {
    public static T Clone<T>(this object obj) {
        var cloneable = obj as ICloneable;
        if (cloneable != null)
            return (T)cloneable.Clone();
        using (var ms = new MemoryStream()) {
            return (T)...
        }
    }
}

(为了清晰起见,我使用ICloneable,但如果您不想使用它,因为它在全球范围内的随机使用,那么只需选择您自己的等效非通用接口即可)。