Вопрос:

C# - How does a cast to a base-type work?

c# class object casting

130 просмотра

2 ответа

110 Репутация автора

This is possibly a duplicate, but I couldn't find a similar question. I don't understand how an implicit cast to a base-type works without data-loss. For example I created the class Person:

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Now, when I do following:

object personAsObject = new Person { Name = "Foo", Age = 1 };
var person = (Person) personAsObject;
Console.WriteLine(person.Name);
Console.WriteLine(person.Age);

How was the object able to keep the values of the properties Name and Age since it only has the 4 methods Equals, GetHashCode, GetType and ToString? And why does a cast to a subclass throw an InvalidCastException? I would've expected that to be possible, since members are inherited if they're not private.

Автор: Damien Flury Источник Размещён: 08.11.2017 10:46

Ответы (2)


9 плюса

33075 Репутация автора

Решение

It's all about references.

personAsObject is not an instance of an object.

When you called new Person, you created an instance of a Person in managed memory.

The variable personAsObject is a reference: a pointer to the managed memory location where the Person object resides.

The same goes for person: it is not an instance of a Person, it's a reference to a Person (which happens to be the same object that personAsObject is referencing) in memory.

VARIABLES                  MANAGED MEMORY
=========                  ==============

personAsObject----|     +-----------------+
                  |---->| Person Instance |
person------------|     +-----------------+
Автор: Andrew Shepherd Размещён: 08.11.2017 10:50

1 плюс

17660 Репутация автора

To paraphrase an overused example - and this isn't necessarily an example of good class design:

public class Employee
{
    public string Name { get; set; }
    public Guid EmployeeId { get; set; }
}

public class Manager : Employee
{
    public IEnumerable<Employee> DirectReports { get; set; }
}

If you cast a Manager as an Employee

var manager = GetManager(guid employeeId);
var employee = manager as Employee;

or

var employee = (Employee)manager;

You're not turning the Manager into an Employee, because the Manager already is an Employee.

In effect what you're saying is that you don't care what else this object is other than that it's an Employee. Because in some cases you might not care. Suppose you want to create a list of employees - List<Employee> - approaching their five-year anniversaries so that you can invite them to a party. It's important that you can add every sort of Employee to that list.

That also enables polymorphism. Another common example:

public interface IAnimal
{
    string MakeSound();
}

public class Cow : IAnimal
{
    public string MakeSound()
    {
        return "Moo";
    }
}

public class Giraffe : IAnimal
{
    public string MakeSound()
    {
        return "I don't make any sound. Bad example.";
    }
}

Now you can do this:

var animals = new List<IAnimal>();
animals.Add(new Cow());
animals.Add(new Giraffe());
foreach(var animal in animals) // or IAnimal in animals
{
    Console.WriteLine(animal.MakeSound());
}

which would display

Moo
I don't make any sound. Bad example.

When you go through the items in your List<IAnimal> you don't know what the actual class is for each. All you know is that each item is an IAnimal and implements MakeSound(). It doesn't change the "concrete" type for each one. It just means that for the purpose of what you're doing, you don't care about the concrete type.

This makes all sorts of things possible. You can have a class like this

public class Cow : IAnimal, ITastesGood
{
    public string MakeSound()
    {
        return "Croak";
    }
}

var cow = new Cow();
var animals = new List<IAnimal>();
var food = new List<ITastesGood>();
animals.Add(cow);
food.Add(cow);

The same instance of Cow can be cast as any class it inherits from or any interface it implements.

Автор: Scott Hannen Размещён: 09.11.2017 01:47
Вопросы из категории :
32x32