简体   繁体   中英

How to access derived class properties from base class instance

I have the following code which I can't access or change:

class A{
}

class B:A{
    string name;
    int age;
    string desc;
}

class C:A{
    string name;
    int age;
    string desc;
}

I need to find a way to write a function that assigns values to instances of B and C. the naive way would be to write two functions. one for each class.

void myFunc(B b){
    b.name = "some_name";
    b.age = 27;
    b.desc = "some_desc";
}

void myFunc(C c){
    c.name = "some_name";
    c.age = 27;
    c.desc = "some_desc";
}

Is there a way to write one generic function that those the job? of-course those classes are only examples. In the real world there are many classes deriving from the base class and each class has many members.

We can find several ways to do this. For example you can use an extension method for the type: A And use reflection to set fields in it.

Like this:

public static class ClassExtensions
{
    public static void SetProperties(this A a, string name, int age, string desc)
    {
        Type type = a.GetType();
        type.GetField("name")?.SetValue(a, name);
        type.GetField("age")?.SetValue(a, age);
        type.GetField("desc")?.SetValue(a, desc);
    }
}

Here is how it works: https://dotnetfiddle.net/9uR3bA

Or just use dynamic like:

public static void Main(string[] args)
{
    var b = new B();
    SetValues(b, "yes", 5, "ok");

    var c = new C();
    SetValues(c, "no", 10, "not ok");
}

public static void SetValues(dynamic theClass, string name, int age, string desc)
{
    theClass.name = name;
    theClass.age = age;
    theClass.desc = desc;
}

Note: I'm assuming the fields or properties will be public, not private.

Just curious: why not using Automapper ? It uses a convention-based approach, and when that's not enough, you can write the mapping code yourself and inject it.

That's not a good design. If you can in any way change it, strongly consider doing so, but if you can't, here's what you can do.

You don't need Reflection for this. Downcasting will do the job:

void MyMethod(A a)
{
    if (a is B b)
    {
        b.name = "some_name";
        b.age = 27;
        b.desc = "some_desc";        
    }

    if (a is C c)
    {
        c.name = "some_name";
        c.age = 27;
        c.desc = "some_desc";
    }
}

Since A is an unsealed base class, other derived classes could exist ( class D : A etc.), but since MyMethod doesn't return anything, passing any other subtype as an argument is simply going to be a no-op.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM