解决 将基础对象转换为继承的对象

邦德拉

知名会员
已加入
2020年10月24日
留言内容
68
编程经验
Beginner
我正在尝试将要传递给方法的对象强制转换为其继承的类/对象之一。
由于我想尽可能避免重复的代码。最后一个例子是工作的,即使是重复的文本块,也是最好的解决方案?

您对此总体上有何看法?你会怎么做?

示例1-不工作,但喜欢一个
使用这个只会让我只有一小段文字,即 "...不玩..."
但是,玩具永远不会被扔到球上(正如我所希望和期望的那样)。因此,让我访问属性“球中的颜色”。

C#:
        public void InitPlay(Toy toy)
        {
            if (toy is Ball ball)
            {
                toy  = (Ball)toy; // At this point I was expecting toy to be casted to the Ball object...
            }
            else if (toy is Bone bone)
            {
                toy  = (Bone)toy; // At this point I was expecting toy to be casted to the Bone object...
            }

            Console.WriteLine($"\n - Press enter to start playing with the {toy}");
            Console.ReadLine();

            Console.WriteLine(" --------------------------------------------------------");
            // ... and thus be able to reach Color in the Ball object using toy.Color. With no luck.
            Console.WriteLine($" The {TypeOfAnimal}{Name} is now playing with the {toy.Color} {toy} ");
            Console.WriteLine(" - Press enter to finish playing ");
            Console.WriteLine(" --------------------------------------------------------");
        }

示例2-工作一个但有重复的文本块

C#:
        public void InitPlay(Toy toy)
        {
            Console.WriteLine($"\n - Press enter to start playing with the {toy}");
            Console.ReadLine();

            if (toy is Ball ball)
            {
// This forces me to have more or less duplicated blocks of text just to reach properties from each inherited object.
                Console.WriteLine(" --------------------------------------------------------");
                Console.WriteLine($" The {TypeOfAnimal}{Name} is now playing with the {ball.Color} {toy} ");
                Console.WriteLine(" - Press enter to finish playing ");
                Console.WriteLine(" --------------------------------------------------------");
            }
            if (toy is Bone bone)
            {
                Console.WriteLine(" --------------------------------------------------------");
                Console.WriteLine($" The {TypeOfAnimal}{Name} is now playing with the {bone.Size} {toy} ");
                Console.WriteLine(" - Press enter to finish playing ");
                Console.WriteLine(" --------------------------------------------------------");
            }
        }
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,501
地点
悉尼,澳大利亚
编程经验
10+
Think about what that first example is doing. The toy parameter is declared as type Toy. 什么 exactly do you think this does:
C#:
toy  = (Ball)toy;
It doesn't matter what you do on the righthand side because you assign the result to the toy variable. If toy is declared as type Toy, how could you possibly get anything other than a Toy reference from it? The actual object was already type Ball so you're not changing the type of the object and you're not changing the type of the variable, so you're doing nothing at all. The cast IS made, but you basically cast it back to the base type again immediately.
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,501
地点
悉尼,澳大利亚
编程经验
10+
我正在尝试将要传递给方法的对象强制转换为其继承的类/对象之一。
重要的问题是为什么。您是在告诉我们您要做什么,并且是在向我们展示您要如何做,但是您并没有在解释您认为自己正在解决的问题。几乎可以肯定,它被误导了。重点是您不要转换基本参考。您将基类中的成员声明为 abstract 或作为 virtual 使用默认实现和 然后在派生类型中覆盖它们。 这样,您只需通过基本引用访问成员,它将自动调用派生的实现。那就是多态 @跳伞 在讨论中,这几乎是继承的全部要点。如果您需要调用不常见的成员,那么几乎可以肯定,一开始就不应该传递基本类型的引用。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,497
地点
弗吉尼亚州切萨皮克
编程经验
10+
继续 @jmcilhinney post #3 above, C# is not like Groovy where the types of variables are automatically dynamically typed. (You can use the dynamic keyword to get dynamic types in C# , but personally I find that this actually makes code harder to understand.)
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,501
地点
悉尼,澳大利亚
编程经验
10+
You can use the dynamic keyword to get dynamic types in C# , but personally I find that this actually makes code harder to understand.
It's pretty rare that dynamic should be used. It's the sort of thing that some people might use to hide problems rather than solve them. It can be used to provide late-binding for things like Office Automation, like 选项严格关闭 in VB, and it serves a purpose for things like the ViewBag property in MVC controllers and views. Personally though, I've never had cause to declare something dynamic myself.
 

邦德拉

知名会员
已加入
2020年10月24日
留言内容
68
编程经验
Beginner
重要的问题是为什么。您是在告诉我们您要做什么,并且是在向我们展示您要如何做,但是您并没有在解释您认为自己正在解决的问题。几乎可以肯定,它被误导了。重点是您不要转换基本参考。您将基类中的成员声明为 abstract 或作为 virtual 使用默认实现和 然后在派生类型中覆盖它们。 这样,您只需通过基本引用访问成员,它将自动调用派生的实现。那就是多态 @跳伞 在讨论中,这几乎是继承的全部要点。如果您需要调用不常见的成员,那么几乎可以肯定,一开始就不应该传递基本类型的引用。
我实际上是这样做的,但是使用了抽象。真的不知道为什么我也没有测试虚拟。这是我们在学校教过的那两个。
虚拟但工作得很好!仅需一秒钟的修复时间! (y)
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,501
地点
悉尼,澳大利亚
编程经验
10+
There's no need to cast if the member is declared abstract or virtual. In case you're not clear on the distinction, you would use abstract if you wanted to declare the member in the base class but only provide an implementation in each base class, while you would use virtual if you wanted to provide a default implementation in the base class that may or may not be overridden in each derived class. Note that, if you declare a member abstract, you must declare the type abstract as well, which means that you can never create an instance of that class directly. If it exists solely to be a base for other classes anyway, that's not an issue. Here's an example of an abstract method:
C#:
class Program
{
    static void Main()
    {
        var fruits = new Fruit[] {new 苹果(), new 橙子()};

        foreach (var fruit in fruits)
        {
            DisplayName(fruit);
        }

        Console.ReadLine();
    }

    private static void DisplayName(Fruit fruit)
    {
        Console.WriteLine(fruit.GetName());
    }
}

public abstract class Fruit
{
    public abstract string GetName();
}

public class 苹果 : Fruit
{
    public override string GetName()
    {
        return "Apple";
    }
}

public class 橙子 : Fruit
{
    public override string GetName()
    {
        return "Orange";
    }
}
In this case, both 苹果 and 橙子 are required to provide their own implementation of GetName. The output of that code is this:
Apple
橙子
这是虚拟方法的示例:
C#:
class Program
{
    static void Main()
    {
        var fruits = new Fruit[] {new 苹果(), new 橙子()};

        foreach (var fruit in fruits)
        {
            DisplayName(fruit);
        }

        Console.ReadLine();
    }

    private static void DisplayName(Fruit fruit)
    {
        Console.WriteLine(fruit.GetName());
    }
}

public class Fruit
{
    public virtual string GetName()
    {
        return "Unnamed Fruit";
    }
}

public class 苹果 : Fruit
{
    public override string GetName()
    {
        return "Apple";
    }
}

public class 橙子 : Fruit
{
}
In this case, 苹果 and 橙子 can provide their own implementation but they don't have to. If they do, calling that method will invoke that implementation, otherwise the default implementation in the base class will be invoked. The output of that code is this:
Apple
未命名的水果
 
最佳 底部