Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C带泛型的类型安全克隆_C#_Generics - Fatal编程技术网

C# C带泛型的类型安全克隆

C# C带泛型的类型安全克隆,c#,generics,C#,Generics,我正在尝试创建一个通用容器对象;没有可以深度克隆的问题。这意味着它必须深度克隆它包含的对象,正是这一点给我带来了问题。下面是一些代码: public abstract class VehiclePart { public abstract T cloneTypesafe<T>() where T : VehiclePart, new() // L1 } public class Gearsti

我正在尝试创建一个通用容器对象;没有可以深度克隆的问题。这意味着它必须深度克隆它包含的对象,正是这一点给我带来了问题。下面是一些代码:

    public abstract class VehiclePart {
        public abstract T cloneTypesafe<T>()
                        where T : VehiclePart, new() // L1
    }


    public class Gearstick : VehiclePart { // L2

        public Gearstick() { }

        public override T cloneTypesafe<T>() {
            var res2 = new Gearstick();
            return res2; // L3
            return (T)res2; // L4
        }
    }
它拒绝接受该注释L3,说“不能将类型'LDB.Program.Gearstick'隐式转换为'T',但这没有意义,因为T显式派生自车辆部件行L1,而Gearstick显式派生自车辆部件行L2,因此转换应完全合法


即使我有一个显式的强制转换行L4,它也不高兴不能将类型“LDB.Program.Gearstick”转换为“T”,那么问题出在哪里?我该如何解决这个问题?我不想使用反思,这似乎是回答类似问题时的常见建议。我读过几条评论,说不要使用ICloneable。

为了让它像我想的那样工作,你应该对抽象类本身有一个通用的定义

public abstract class VehiclePart<T> where T: new() {
    public abstract T cloneTypesafe();
}

public class Gearstick : VehiclePart<Gearstick> { // L2

    public Gearstick() { }

    public override Gearstick cloneTypesafe() {
        var res2 = new Gearstick();
        return res2; 
    }
}

为了让它像我认为您期望的那样工作,您应该对抽象类本身有一个泛型定义

public abstract class VehiclePart<T> where T: new() {
    public abstract T cloneTypesafe();
}

public class Gearstick : VehiclePart<Gearstick> { // L2

    public Gearstick() { }

    public override Gearstick cloneTypesafe() {
        var res2 = new Gearstick();
        return res2; 
    }
}
那有什么问题

您方法的签名允许我按如下方式调用您的代码:

CarWindow myCarWindow = myGearstick.cloneTypesafe<CarWindow>();
请注意,正如Jamiec在评论中指出的,类型系统不会阻止您做出无意义的声明,例如公共类Gearstick:VehiclePart,IDeepClonable

那有什么问题

您方法的签名允许我按如下方式调用您的代码:

CarWindow myCarWindow = myGearstick.cloneTypesafe<CarWindow>();

请注意,正如Jamiec在评论中指出的,类型系统不会阻止您做出无意义的声明,例如公共类Gearstick:VehiclePart,IDeepClonable。

这是对泛型的滥用。如果您使用泛型,您的意思是方法的调用者可以通过一些约束传入他们想要的任何类型,并且您的方法仍然可以工作。这里显然不是这样。只有当T为Gearstick时,Gearstick中的cloneTypesafe方法才有效。如果T是,例如发动机或车轮,则铸件将失效

ClonetTypeSafe应该返回它所在的类的类型,但我们无法在C中这样说。不过,您可以将此作为一种解决方法:

public abstract class VehiclePart<T> 
    where T : VehiclePart<T>, new(){ // implementers are supposed to replace T with their class
    public abstract T cloneTypesafe();
}

// you are not "forced" to say ": VehiclePart<Gearstick>", hence why this is only a workaround
public class Gearstick : VehiclePart<Gearstick> {
    public override Gearstick cloneTypesafe() {
        var res2 = new Gearstick();
        // copy some properties...
        return res2;
    }
}

这是对仿制药的滥用。如果您使用泛型,您的意思是方法的调用者可以通过一些约束传入他们想要的任何类型,并且您的方法仍然可以工作。这里显然不是这样。只有当T为Gearstick时,Gearstick中的cloneTypesafe方法才有效。如果T是,例如发动机或车轮,则铸件将失效

ClonetTypeSafe应该返回它所在的类的类型,但我们无法在C中这样说。不过,您可以将此作为一种解决方法:

public abstract class VehiclePart<T> 
    where T : VehiclePart<T>, new(){ // implementers are supposed to replace T with their class
    public abstract T cloneTypesafe();
}

// you are not "forced" to say ": VehiclePart<Gearstick>", hence why this is only a workaround
public class Gearstick : VehiclePart<Gearstick> {
    public override Gearstick cloneTypesafe() {
        var res2 = new Gearstick();
        // copy some properties...
        return res2;
    }
}

使用C 9,您可以在此处消除泛型的需要,并使用:


使用C 9,您可以在此处消除泛型的需要,并使用:


T可能源于车辆部件,但并非每个车辆部件也源于变速杆-因此,在C 9中,您不能向每个可能的TA转换一个可能的替代方案,协变返回类型允许在不使用泛型的情况下将VehiclePart ClonetTypeSafe重写为Gearstick ClonetTypeSafe。@UnholySheep:如果我添加约束公共类Gearstick:VehiclePart,其中T:VehiclePart,new{然后错误就来了,但我不明白为什么。问题是我在这里基本上没有深度。我想我只需要接受我还没有达到这个水平,并努力解决它。@Jeroenmoster:是的,我在前面的问题中模糊地意识到了这一点,但我还不想升级。不过谢谢。我花了很多时间尝试做类似的事情在放弃之前,我想说的是,不幸的是,这并不是C类型系统目前能够实现的。最好的办法是让公共抽象车辆部分克隆,并让调用方在需要时强制转换它,或者使它不是抽象的,每个派生类型返回它自己的类型。尽管这取决于您实际使用的类型如果这是一个合理的解决方案,就使用它。T可能来自VehiclePart,但不是每个VehiclePart也来自Gearstick-因此,您不能对每个可能的TA强制转换一个可能的替代,在C 9中,协变返回类型允许VehiclePart cloneTypeSafe被重写为Gearstick cloneTypeSafe,而不使用泛型。@UnholySheep:如果我添加一个约束公共类Gearstick:VehiclePart,其中T:VehiclePart,new{然后错误就来了,但我不明白为什么。问题是我在这里基本上没有深度。我想我只需要接受我还没有达到这个水平,并努力解决它。@Jeroenmoster:是的,我在前面的问题中模糊地意识到了这一点,但我还不想升级。不过谢谢。我花了很多时间尝试做类似的事情在放弃之前,我想说的是,不幸的是,这并不是C类型系统目前能够实现的。你最好的办法是让公共抽象车辆部分克隆,并让调用方在需要时进行转换,或者使其不抽象
每个派生类型都返回自己的类型。如果这是一个合理的解决方案,这取决于您实际使用它做了什么。但是值得记住的是,我仍然可以编写公共类Gearstick:VehiclePart,编译器也可以,这可能值得指出这里的缺点-没有什么强迫T为派生类型-公共类SteeringWheel:VehiclePart{}也会被打字系统接受。^^那些家伙说了什么!是的,我自己从变速杆上克隆了一个轮子。。。我想没关系。更深层次的问题是,除了基础知识之外,我还没有足够的泛型经验。关于提前阅读有什么建议吗?但值得记住的是,我仍然可以编写公共类Gearstick:VehiclePart,编译器也可以,这可能值得指出这里的缺点-没有什么强迫T成为派生类型-公共类SteeringWheel:VehiclePart{}也会被打字系统接受。^^那些家伙说了什么!是的,我自己从变速杆上克隆了一个轮子。。。我想没关系。更深层次的问题是,除了基础知识之外,我还没有足够的泛型经验。对提前阅读有什么建议吗?我个人更喜欢你单独的界面解决方案。尽管允许公共类Gearstick存在相同的问题:VehiclePart,IdeepClonableun,但C不支持协变返回类型->参见c9。0@pinkfloydx33:说得好!我想我个人更喜欢你单独的界面解决方案。尽管允许公共类Gearstick存在相同的问题:VehiclePart,IdeepClonableun,但C不支持协变返回类型->参见c9。0@pinkfloydx33:说得好!