C# 克隆泛型类型

C# 克隆泛型类型,c#,generics,C#,Generics,我想克隆一个泛型对象并保留其类型 run.Append(style.Clone(BlackFont)); //run object accepts only RunProperties objects public T Clone(T what) { if (what is RunProperties) return (T) what.Clone(); } 因为t类型没有克隆方法,所以它不起作用,我如何克服这个问题而不在第一条语句中强制转换 run.Append((R

我想克隆一个泛型对象并保留其类型

run.Append(style.Clone(BlackFont)); //run object accepts only RunProperties objects

public T Clone(T what) {
    if (what is RunProperties)
        return (T) what.Clone();
}
因为t类型没有克隆方法,所以它不起作用,我如何克服这个问题而不在第一条语句中强制转换

run.Append((RunProperties) style.Clone(BlackFont)); //I do not want this
//not that this will work since you can't convert T to RunProperties
谢谢你的帮助

---编辑---


在这种情况下,我最好不要使用泛型。我将拆分数据。

您始终可以将该方法约束为仅接受实现IClonable接口的类型:

public T Clone(T what) where T : ICloneable
{
    if (what is RunProperties)
        return (T) what.Clone();
}
但由于您的方法实际上只适用于一种类型,因此您可以稍微更改它,并使用
as
运算符:

public T Clone(T what)
{
    var castWhat = what as RunProperties;
    if(castWhat != null)
        return castWhat.Clone();
}

您可以使用将T的类型约束为实现的类型。

您可以使用通用约束:

public T Clone<T>(T what) where T: ICloneable
{
    if (what is RunProperties)
        return (T)what.Clone();
    ...
}
public T Clone(T what)where T:ICloneable
{
if(什么是RunProperties)
返回(T)what.Clone();
...
}
或者,如果在包含类上定义了T泛型参数:

public class Foo<T> where T: ICloneable
{
    public T Clone(T what)
    {
        if (what is RunProperties)
            return (T)what.Clone();
        ...
    }
}
公共类Foo其中T:ICloneable
{
公共T克隆(T什么)
{
if(什么是RunProperties)
返回(T)what.Clone();
...
}
}

你几乎自己给出了答案:

T type does not have a Clone method
另外,如果只对一种类型执行某些操作,那么泛型方法的意义何在

克隆方法来自ICloneable接口,因此您可以实现通用克隆方法,使其适用于实现
ICloneable
的所有类型,如下所示:

public T Clone<T>(T what) where T: ICloneable
{
   return (T) what.Clone();
}
public T Clone(T what)where T:ICloneable
{
返回(T)what.Clone();
}

我建议定义一个接口ISelf,它有一个名为“Self”的只读属性,类型为T(在任何实现中,它都应该返回“this”)。它们定义ICloneable,ICloneable继承ISelf并实现T类型的方法Clone()

然后,如果您有一个方法需要从Foo类型派生的东西并且是可克隆的,只需将该方法传递给ICloneable即可。要将传入的对象用作“Foo”,请访问其“Self”属性。我建议使用公共克隆方法的类通常应该被密封,但只需添加一个公共“克隆”包装器即可扩展未密封的类型。这将允许存在允许或不允许克隆的派生类型

考虑类family Foo、CloneableFoo、DerivedFoo和CloneableDerivedFoo以及其他DerivedFoo

  • Foo不提供公共克隆方法;它可以毫不费力地克隆,并且具有受保护的MakeClone方法。
  • CloneableFoo源于Foo,并公开了一个公共克隆方法,该方法封装MakeClone并实现ICloneable。
  • DerivedFoo源于Foo;与Foo一样,它没有公共克隆方法,但提供了受保护的MakeClone方法。
  • CloneableDerivedFoo源于DerivedFoo,并公开了一个公共克隆方法,该方法包装MakeClone并实现ICloneable。
  • OtherDerivedFoo源于DerivedFoo,但具有类不变量,如果克隆,这些不变量将被破坏;它使用标记为“过时错误”的空函数隐藏MakeClone。

考虑到这些关系,一种方法可以接受Foo的任何可克隆的派生,而另一种方法可以接受DerivedFoo的任何派生——可克隆或不可克隆。第一种方法应使用ICloneable类型的参数,而后者则采用DerivedFoo类型的参数。请注意,如果DerivedFoo是从CloneableFoo而不是Foo派生的,那么如果不承诺使用公共克隆方法,就不可能从DerivedFoo派生任何内容。

下面是我编写的一个函数,它使用反射克隆T类型的记录。 这是一个非常简单的实现,我没有处理复杂的类型等

公共静态T克隆(T原始)
{
T newObject=(T)Activator.CreateInstance(original.GetType());
foreach(原始.GetType().GetProperties()中的var originalProp)
{
originalProp.SetValue(新对象,originalProp.GetValue(原始));
}
返回newObject;
}

我希望这能帮助别人。

使用我开发的FastDeepcloner

//
///克隆对象,请参阅FastDeepCloner以了解更多信息
/// 
/// 
/// 
/// 
/// 
公共静态列表克隆(此列表项,FieldType FieldType=FieldType.PropertyInfo)
{
返回DeepCloner.Clone(项目,新的FastDeepClonerSettings()
{
FieldType=FieldType,
OnCreateInstance=new Extensions.CreateInstance(FormatterServices.GetUninitializedObject)
});
}

我计划添加更多类型,以保持简单为例。现在实现,希望可以很好地工作。@skynorth-如果是这样,那么使用第一个选项。
    /// <summary>
    /// Clone Object, se FastDeepCloner for more information
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="items"></param>
    /// <param name="fieldType"></param>
    /// <returns></returns>
    public static List<T> Clone<T>(this List<T> items, FieldType fieldType = FieldType.PropertyInfo)
    {
        return DeepCloner.Clone(items, new FastDeepClonerSettings()
        {
            FieldType = fieldType,
            OnCreateInstance = new Extensions.CreateInstance(FormatterServices.GetUninitializedObject)
        });
    }