向下转换 C# .NET

Downcasting C# .NET

这是我的例子:

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

public class Client : Person
{
    public string LastName { get; set; }
}

public class Test
{
    Person p = new Person();
    Client c = (Client)p; //throws exception
}

既然Client继承自Person,为什么我做不到呢?如果我可以,但这是错误的方法,我该怎么做?

OBS:我知道上面的例子可以做到:

Person p = new Client();
Client c = (Client)p;

A Person 不是 Client 因此您希望编译器如何转换它?试试这个,你会得到一个 null 分配:

Client c = p as Client;

换句话说:编译器错误消失了,但 c 将永远是 null

这会引发异常,因为 p 不是客户端。 p 已创建为 person。您可以创建一个 client 对象并将其转换为它的基类 person,但不是这样。

实际上,稍微绕一下,您就可以进行这样的转换,但是,它需要一个额外的父 class 用于其他两个 class,以及一个隐式运算符来将 Client 转换为一个人(虽然这可能不是你最初想要的)

class Program
{
    public abstract class BasePerson
    {
        public string FirstName { get; set; }
    }

    public class Person : BasePerson
    {
    }

    public class Client : BasePerson
    {
        public string LastName { get; set; }

        public static implicit operator Client(Person p)
        {
            if (p == null)
            {
                return null;
            }
            return new Client { FirstName = p.FirstName };
        }
    }

    static void Main(string[] args)
    {
        Person p = new Person { FirstName = "Test" };
        Client c = (Client)p;
        Console.WriteLine(c.FirstName);
        Console.ReadLine();
    }
}

这将编译并向客户提供 FirstName,并可能提供姓氏,但是,正如我所说,这可能不是您想要的,只是让您的代码编译的可能性,并且 运行 变化最小...

更新

正如评论中所讨论的,如果我需要实现这样的转换,我更愿意通过

  • 创建辅助方法

    public class Client : Person
    {
        public static Client GetClientFromPerson(Person p) 
        {
            if (p == null) 
            {
                return null;
            }
            return new Client { FirstName = p.FirstName };
        }
    }
    

这将导致:

Client c = Client.GetClientFromPerson(p);
  • 添加第二个构造函数

    public class Client : Person
    {
        public string LastName { get; set; }
    
        public Client()
        {
        }
    
        public Client(Person p) : this()
        {
            FirstName = p.FirstName;
        }
    }
    

这将导致:

Client c = new Client(p);

这将使其他人审查代码变得容易得多,也可能在将来进行维护,并且不需要您更改您现在拥有的继承

子代可以继承其父代的所有属性class,但父代只能继承公共属性。这并不意味着您可以将父对象直接分配给它的子对象。

您可以使用 asis 运算符来完成。

通过使用 as 运算符,如果变量不为空,则 class 可转换为其他 class

Person p = new Person();
var conversionResultFromPersonToClient = p as Client;
if(conversionResultFromPersonToClient != null)
   //it means you can cast from person to client

第二种方法是使用 is 运算符

Person p = new Person();
Client c = new Client();
if(p is Client)
   //Then you can cast person to client
   c = (Client)p;