C# 如何对具有相同成员的不同类型参数使用相同的函数?

C# 如何对具有相同成员的不同类型参数使用相同的函数?,c#,C#,这里是示例代码,我定义了两个类。如何使用Output函数输出两个不同类中具有相同名称的成员 class A { public string Name { get; set; } public int Age { get; set; } public string Email { get; set; } public A(string name, int age, string email) { Name = name; A

这里是示例代码,我定义了两个类。如何使用
Output
函数输出两个不同类中具有相同名称的成员

class A
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }

    public A(string name, int age, string email)
    {
        Name = name;
        Age = age;
        Email = email;
    }
}

class B
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Location { get; set; }

    public B(string name, int age, string location)
    {
        Name = name;
        Age = age;
        Location = location;
    }
}

void Output(object obj)
{
    // How can I convert the object 'obj' to class A or class B
    // in order to output its 'Name' and 'Age'
    Console.WriteLine((A)obj.Name); // If I pass a class B in pararmeter, output error.
}
您必须:

  • 使用反射获取属性(如果不存在,则抛出)
  • 有一个公共接口,例如
    INamed
    ,它有一个字符串
    Name
    属性,这两个类都实现了该属性
  • 将局部变量声明为
    dynamic
    ,并使用它访问
    Name
    属性(但实际上这与#1相同,因为动态分派将仅使用反射来获取
    Name
    属性)

  • 在你的例子中-B不是从A中产生的,所以你不能将B转换成A

    将B更改为从A继承,如

    class B : A
    {
    ...
    }
    

    也考虑你在B类的方法中要完成什么。 并且-如果您继承了,则可能不需要两次声明相同的成员。

    您可以利用它绕过编译器,它会在运行时检查类型,因此您不需要强制转换:

    void Output(dynamic obj)
    {
        Console.WriteLine(obj.Name); 
    }
    
    你可以做:

    if ( obj.GetType() == typeof( A ) )
    {
        Console.WriteLine(((A)obj).Name);
    }
    else if ( obj.GetType() == typeof( B ) )
    {
        Console.WriteLine(((B)obj).Name);
    }
    

    您应该声明一个接口,该接口将描述两个类的公共部分:

    interface I
    {
        string Name { get; set; }
        int Age { get; set; }
    }
    
    然后在
    A
    B
    中实现它:

    class A : I
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Email { get; set; }
    
        public A(string name, int age, string email)
        {
            Name = name;
            Age = age;
            Email = email;
        }
    }
    
    class B : I
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Location { get; set; }
    
        public B(string name, int age, string location)
        {
            Name = name;
            Age = age;
            Location = location;
        }
    }
    
    并更改方法以获取
    I
    作为参数:

    void Output(I obj)
    {
        Console.WriteLine(obj.Name); 
    }
    

    您可以使用
    动态
    、反射或继承。或者您可以复制该方法并利用方法重载

    void Output(A obj)
    {
     // in order to output its 'Name' and 'Age'
     Console.WriteLine(obj.Age);
     Console.WriteLine(obj.Name);
    }
    
    void Output(B obj)
    {
     // in order to output its 'Name' and 'Age'
     Console.WriteLine(obj.Age);
     Console.WriteLine(obj.Name);
    }
    

    您需要为这两个类创建一个公共接口,以便编译器知道这两个类都可以提供某些功能(在您的情况下是名称和年龄):


    A
    B
    除了有一些类似的成员外,是否有其他关系?也就是说,它们可以从共享父类型继承吗?@Oded-我认为这也是一种方式。在这里使用
    dynamic
    从来都不是最佳实践。另一个选项是为
    A
    B
    重载
    输出
    ,并且有一个私有函数,在从每个函数中提取数据后,重载可以使用它。@Oded-这很有趣,因为我只是在你发表评论之前写了这个作为答案。我喜欢你的风格:
    Name
    property是私有的吗?那么它将如何工作(除了反射)?<代码> b <代码>的实例构造函数被称为<代码> A<代码>(非法)。这是最后考虑的方法。我从来没有这样建议过。如果(obj是一个)等等,为什么不
    ?你会因为运行时类型检查而受到多少性能损失?@MarcinJuraszek:这只是一种方法,但不要过早优化。在大型应用程序中,动态性能的这一点是微不足道的,也可以使
    名称
    获取
    -仅在接口
    I
    内。在这种情况下,
    A
    B
    允许设置
    ter
    private
    ,这在某些情况下是可取的(例如,可以将类型设置为不可变)。@JeppeStigNielsen说得对!但我的回答更像是他能走的一条路,所以我将保持现状。这就是我要做的。使用
    dynamic
    解决这个问题是错误的方法。我注意到,建议
    dynamic
    的答案中没有一个提到,更不用说解决使用
    dynamic
    时由于
    Name
    丢失、类型错误或是方法而不是属性等原因引发异常时该怎么办了。用编译时正确性来换取潜在的运行时错误是很糟糕的。谢谢。#3?@Eddie使用反射的任何效率问题通常都比直接属性调用慢,但它肯定会起作用。最后,您必须实际测量应用程序的性能,看看这是否是热点。很有可能,数据库访问和网络调用之类的事情会大大超过一点反思。但你必须测量才能确定。
        interface IHasNameAndAge
        {
            string Name { get; }
            int Age { get; }
        }
    
        class A : IHasNameAndAge
        {
            public string Name { get; set; }
            public int Age { get; set; }
            string Email { get; set; }
    
            public A(string name, int age, string email)
            {
                Name = name;
                Age = age;
                Email = email;
            }
        }
    
        class B : IHasNameAndAge
        {
            public string Name { get; set; }
            public int Age { get; set; }
            string Location { get; set; }
    
            public A(string name, int age, string location)
            {
                Name = name;
                Age = age;
                Location = location;
            }
        }
    
        void Output(IHasNameAndAge obj)
        {
            Console.WriteLine(obj.Name + " is " + obj.Age);
        }