为什么对象在向上转换时保存属性

Why an object saves properties when upcasted

我有一个关于在 C# 中向上转换的简单问题。例如我有两个接口:

interface IUSer
{
    string UserName { get; set; }
}

interface IAdmin: IUSer
{
    string Password { get; set; }
}

...和 ​​class 实现 IAdmin 接口:

class Admin : IAdmin
{
    public string Password { get; set; }
    public string UserName { get; set; }
}

当我创建一个 Admin 类型的对象并尝试将其向上转换为 IUser 时,从技术上讲我只能访问 UserName user.UserName:

var admin = new Admin() { UserName = "Arthur", Password = "hello" };
var user = (IUSer)admin;
Console.WriteLine( user.UserName );

...但是如果我使用反射循环遍历该对象的属性,就像这样:

    private static void Outputter(IUSer user)
    {
        foreach (var prop in user.GetType().GetProperties())
        {
            Console.WriteLine(prop.Name +  " " + prop.GetValue(admin));
        }
    }

...我还可以看到密码 属性。问题是 - 为什么它在向上转换时被保存?

The question is - why it is saved when upcasted?

因为转换根本不会改变 object。它只会改变您查看对象的方式。

把它想象成一个人。人们可以通过不同的方式查看您:

  • 一位同事
  • 一位经理
  • 家庭成员
  • 一个朋友

他们只是 "see" 你的某些方面,但这不会改变你是谁。

同样,简单的引用转换不会更改对象。如果你调用 user.GetType() 它仍然会报告对象的 actual 类型。只是当您通过特定镜头(无论是接口还是底座 class)查看对象时,您只会看到镜头显示给您的成员。

(请注意,调用用户定义转换的转换,例如从 XElement 转换为 string,是完全不同的。returns 是对新对象的引用,而不是仅仅以不同的方式看待现有对象。)

如果您只想查看 IUser 属性,请使用 typeof(IUser).GetProperties() 而不是先调用 GetType()

private static void Outputter(IUser user)
{
    foreach (var prop in typeof(IUser).GetProperties())
    {
        Console.WriteLine($"{prop.Name}: {prop.GetValue(user)}");
    }
}

虽然我不确定在大多数情况下通过反射来做到这一点是否特别有用。

当您将任何类型的对象转换为其基类型时,您只是持有该对象及其基类型。

对象不会因此失去其属性。

如果你看到一个最简单的例子:非泛型集合的使用

当您在 ArrayList 中添加一些对象(比方说 Admin class)时,您实际上是将该对象转换为类型 object(装箱),然后将其存储在数组列表中。所以它是向上转型的终极例子!如何?

The object type is an alias for Object in the .NET Framework. In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from Object.

Full Post

现在 object 类型不包含 userName password 等属性。 因此,当您尝试从直接从 arraylist 获取的对象中访问那些 属性 时,您将无法这样做。因为当前您正在处理 object 类型,您将只能访问 object 类型支持的那些属性或成员(但在这里您无法访问,但那些属性仍然存在)。另外如其他答案中所述 GetType() 方法肯定 return 它也是原始类型。

但是当您通过将其转换回 Admin 类型(拆箱)从数组列表中取回原始对象时,您会看到这些属性像以前一样存在于您的对象中。唯一改变的是,现在您可以访问它们,因为 Admin 类型支持它们。

Read this for more detail