克隆泛型类型

时间:2011-09-21 14:43:01

标签: 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((RunProperties) style.Clone(BlackFont)); //I do not want this
//not that this will work since you can't convert T to RunProperties

感谢您的帮助。

--- --- EDIT

在这种情况下,我似乎不会使用泛型。我会拆分数据。

7 个答案:

答案 0 :(得分:3)

您始终可以将方法限制为仅接受实现ICloneable接口的类型:

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();
}

答案 1 :(得分:2)

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

public static T Clone<T>(T original)
{
    T newObject = (T)Activator.CreateInstance(original.GetType());

    foreach (var originalProp in original.GetType().GetProperties())
    {
        originalProp.SetValue(newObject, originalProp.GetValue(original));
    }

    return newObject;
}

我希望这可以帮助别人。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

你几乎自己给出了答案:

T type does not have a Clone method

另外,如果你只针对一种类型做某事,那么泛型方法有什么意义呢?

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

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

答案 4 :(得分:0)

您可以使用通用约束:

public T Clone<T>(T what) where T: ICloneable
{
    if (what is RunProperties)
        return (T)what.Clone();
    ...
}

或者如果在包含类上定义了T generic参数:

public class Foo<T> where T: ICloneable
{
    public T Clone(T what)
    {
        if (what is RunProperties)
            return (T)what.Clone();
        ...
    }
}

答案 5 :(得分:0)

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

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

考虑类家族Foo,CloneableFoo,DerivedFoo和CloneableDerivedFoo以及OtherDerivedFoo。

  • Foo不提供公共克隆方法;它可以毫无困难地克隆,并具有受保护的MakeClone方法。
  • CloneableFoo派生自Foo,并公开一个公共Clone方法,该方法包装MakeClone并实现ICloneable&lt; CloneableFoo&gt;。
  • DerivedFoo来自Foo;像Foo一样,它没有公共的Clone方法,但提供了受保护的MakeClone方法。
  • CloneableDerivedFoo派生自DerivedFoo,并公开一个公共Clone方法,该方法包装MakeClone并实现ICloneable&lt; CloneableDerivedFoo&gt;。
  • OtherDerivedFoo派生自DerivedFoo,但具有不变量,如果克隆则会被破坏;它使用标记为过时错误的void函数影响MakeClone。

鉴于这些关系,一种方法接受Foo的任何可克隆衍生物将是有用的,而另一种方法将接受DerivedFoo的任何衍生物 - 可克隆或非克隆。第一种方法应使用ICloneable&lt; Foo&gt;类型的参数,而后者采用DerivedFoo类型的参数。请注意,如果DerivedFoo是从CloneableFoo而不是Foo派生的,那么在不承诺使用公共克隆方法的情况下,不可能从DerivedFoo派生任何东西。

答案 6 :(得分:0)

使用我开发的FastDeepcloner https://www.nuget.org/packages/FastDeepCloner/

    /// <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)
        });
    }