Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.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#_Inheritance - Fatal编程技术网

C# 如何正确地从派生类复制字段?

C# 如何正确地从派生类复制字段?,c#,inheritance,C#,Inheritance,让我们以以下课程为例: 基类: public class Spell { public int castRange; public Spell Copy() { Spell spell = new Spell(); spell.castRange = this.castRange; return spell; } } public class ManaSpell : Spell { public int

让我们以以下课程为例:

基类:

public class Spell
{
    public int castRange;

    public Spell Copy()
    {
        Spell spell = new Spell();
        spell.castRange = this.castRange;
        return spell;
    }
}
public class ManaSpell : Spell
{
    public int manaCost;

    public new ManaSpell Copy()
    {
        ManaSpell spell = new ManaSpell();
        spell.castRange = this.castRange;
        spell.manaCost = this.manaCost;
        return spell;
    }
}
派生类:

public class Spell
{
    public int castRange;

    public Spell Copy()
    {
        Spell spell = new Spell();
        spell.castRange = this.castRange;
        return spell;
    }
}
public class ManaSpell : Spell
{
    public int manaCost;

    public new ManaSpell Copy()
    {
        ManaSpell spell = new ManaSpell();
        spell.castRange = this.castRange;
        spell.manaCost = this.manaCost;
        return spell;
    }
}
我不能对Copy()方法使用virtual和override,因为它们有不同的返回类型,所以我使用new关键字。问题从下一节课开始:

public class Unit
{
    public Spell spell;

    public Unit(Spell spell)
    {
        // This will call the Copy method in the base class, even if the 
        // parameter is actually a ManaSpell

        this.spell = spell.Copy();

        // So instead I have to do a check first:

        if (spell is ManaSpell)
        {
            ManaSpell manaSpell = spell as ManaSpell;
            this.spell = manaSpell.Copy();
        }
    }
}
这一切都是可行的,但它感觉像是一个非常低效的设计,特别是如果我添加越来越多的从Spell派生的类,更不用说在基类中添加一个字段意味着在所有派生类中也更改copy方法


有更好的方法吗?

除非你有很好的理由隐藏(这就是
new
所做的)你的
复制
-基类的实现,否则你不应该
new

看来你根本不需要这个。你实际上想复制一个
拼写
,不管它的实际类型是什么。因此,让实例解析对
Copy
的调用,这是通过通常的重写完成的:

public class Spell
{
    public int castRange;

    public virtual Spell Copy()
    {
        Spell spell = new Spell();
        spell.castRange = this.castRange;
        return spell;
    }
}
public class ManaSpell : Spell
{
    public int manaCost;

    public override Spell Copy()
    {
        ManaSpell spell = new ManaSpell();
        spell.castRange = this.castRange;
        spell.manaCost = this.manaCost;
        return spell;
    }
}
现在,您可以在
拼写的任何实例上调用
Copy
,而无需区分实际类型:

this.Spell = spell.Copy()

如果您有基类实例,这将解析为
Spell
的新实例;如果您有派生类型的实例,这将解析为
ManaSpell

除非您有很好的理由隐藏(这就是
new
所做的)您的
复制
-基类的实现,你不应该
new
it

看来你根本不需要这个。你实际上想复制一个
拼写
,不管它的实际类型是什么。因此,让实例解析对
Copy
的调用,这是通过通常的重写完成的:

public class Spell
{
    public int castRange;

    public virtual Spell Copy()
    {
        Spell spell = new Spell();
        spell.castRange = this.castRange;
        return spell;
    }
}
public class ManaSpell : Spell
{
    public int manaCost;

    public override Spell Copy()
    {
        ManaSpell spell = new ManaSpell();
        spell.castRange = this.castRange;
        spell.manaCost = this.manaCost;
        return spell;
    }
}
现在,您可以在
拼写的任何实例上调用
Copy
,而无需区分实际类型:

this.Spell = spell.Copy()

如果您有基类实例,这将解析为
Spell
的新实例;如果您有派生类型的实例,这将解析为
ManaSpell

创建克隆的简单方法是使用从
System.Object
继承的私有方法
MemberwiseClone
。它的优点是自动考虑派生类中的字段。也就是说,您不必派生复制方法来使其工作

public class Spell
{
    public int castRange;

    public Spell ShallowClone()
    {
        return (Spell)MemberwiseClone();
    }

    public override string ToString() => $"castRange = {castRange}";
}

public class ManaSpell : Spell
{
    public int manaCost;

    public override string ToString() => $"castRange = {castRange}, manaCost = {manaCost}";
}
这个测试

Spell spell = new ManaSpell { castRange = 5, manaCost = 10 };
var copy = spell.ShallowClone();
Console.WriteLine(copy);
Console.ReadKey();
。。。显示

castRange=5,manaCost=10

如果您需要键入
ManaSpell
,则无法避免施法


避免强制转换的一个可能解决方案是使用通用静态方法。C#编译器可以从静态(编译时)参数类型推断返回类型

public class Spell
{
    public int castRange;

    public Spell ShallowClone()
    {
        return (Spell)MemberwiseClone();
    }

    public override string ToString() => $"castRange = {castRange}";

    public static T ShallowClone<T>(T original)
        where T : Spell
    {
        return (T)original.ShallowClone();
    }
}
。。。印刷品

castRange=6,manaCost=18


创建克隆的一种简单方法是使用从
System.Object
继承的私有方法
MemberwiseClone
。它的优点是自动考虑派生类中的字段。也就是说,您不必派生复制方法来使其工作

public class Spell
{
    public int castRange;

    public Spell ShallowClone()
    {
        return (Spell)MemberwiseClone();
    }

    public override string ToString() => $"castRange = {castRange}";
}

public class ManaSpell : Spell
{
    public int manaCost;

    public override string ToString() => $"castRange = {castRange}, manaCost = {manaCost}";
}
这个测试

Spell spell = new ManaSpell { castRange = 5, manaCost = 10 };
var copy = spell.ShallowClone();
Console.WriteLine(copy);
Console.ReadKey();
。。。显示

castRange=5,manaCost=10

如果您需要键入
ManaSpell
,则无法避免施法


避免强制转换的一个可能解决方案是使用通用静态方法。C#编译器可以从静态(编译时)参数类型推断返回类型

public class Spell
{
    public int castRange;

    public Spell ShallowClone()
    {
        return (Spell)MemberwiseClone();
    }

    public override string ToString() => $"castRange = {castRange}";

    public static T ShallowClone<T>(T original)
        where T : Spell
    {
        return (T)original.ShallowClone();
    }
}
。。。印刷品

castRange=6,manaCost=18


您应该再次明确阅读有关
新建
虚拟
覆盖
的内容<代码>新建
始终是一个设计缺陷。无论如何,我不明白你的真正目的。为什么要在顶部复制
manaple
的实例,并通过
Spell
类型的引用来引用它。后者不知道其派生类型的任何内容,因此,即使你可以做你想做的事情,
this.Spell
始终将
Spell
作为编译时类型提供给你。只需省略类型检查和
new
,让实例解析
Copy
来调用自己。有点离题,但是您应该考虑使用公共字段。它们提供了更好的封装,而一些库/框架(WPF绑定,
Newtonsoft.Json
…)默认不支持字段。使用公共字段通常被一些人认为是一种不好的做法,因此:)您应该明确地再次阅读有关
new
virtual
override
<代码>新建
始终是一个设计缺陷。无论如何,我不明白你的真正目的。为什么要在顶部复制
manaple
的实例,并通过
Spell
类型的引用来引用它。后者不知道其派生类型的任何内容,因此,即使你可以做你想做的事情,
this.Spell
始终将
Spell
作为编译时类型提供给你。只需省略类型检查和
new
,让实例解析
Copy
来调用自己。有点离题,但是您应该考虑使用公共字段。它们提供了更好的封装,而一些库/框架(WPF绑定,
Newtonsoft.Json
…)默认不支持字段。一些人经常认为使用公共字段是一种不好的做法,所以:)