如何创建一个新的 object 实例 class 是另一个实例的同一类型,只知道它是基础 class 类型?

How to create a new object instance of class being the same type of another instance by only knowing it as base class type?

如何在 C# 中进行动态向下转换?

我有这些 class 如下:

public class Base
{
}

public class A : Base
{
    public string name;
}

public class B : Base
{
    public string name;
}

public class C : Base
{
    public string name;
}

我还有一个Go方法。

我想让它成为动态的 child class 类型(A、B、C),而不是“基本”类型。

这样任何 child class 都可以工作。

如何使 testA 具有动态数据类型?

public class Main
{
    private void Go()
    {
        Test(new A{ name = "My Name is A"});
    }

    private void Test(Base base)
    {
        var baseType = base.GetType();            // Class A (or Class B, Class C)
        var baseTypeName = base.GetType().Name;   // "A" (or "B", "C")

        // I want to make it dynamic child class type(A, B, C), not "Base" type.
        // So that any child class can work
        // How?

        // This code is fixed for A.
        var testA = new A();
        testA.name = "Sucess";

        // I want testA dynamic Data Type.
        var testA = ?;
        testA.name = "Sucess";
    }
}

Downcasting 在 C# 中是不可能的。

基数 object 小于 child object,因此您不能创建基数 object 并将其转换为 child。

在 child 中添加的属性和方法中缺少基础 class,因此您无法创建基础 object 并将其转换为 child object.

沙发可以当椅子坐,但椅子不能当沙发躺。

但是向上转型是 OOP 的基础:我们可以说 child 是基类型。

在这里您不想向上转换或向下转换,而是按照建议的问题新标题中的公式创建一个新实例。

因此,要创建另一个 base object 类型的实例而不是 base 类型,您可以使用反射和 Activator class.

提供代码的初衷改进示例

public class Base
{
  public string Name;
}

public class Child : Base
{
}

void Go()
{
  var a = new Child { Name = "My Name is A" }; // Legal upcast: Child is type of Base
  var b = (Child)Test(a);
  b.Name = "Sucess";
  Console.WriteLine(a.Name);
  Console.WriteLine(b.Name);
}

Base Test(Base instance)
{
  return (Base)Activator.CreateInstance(instance.GetType());
}

但是我们不能写:

Base c = new Base();
Child d = (Child)c;  // Illegal downcast: Base is not type of Child

输出

My Name is A
Sucess

使用泛型将强类型适配解决暴露的问题

void Go()
{
  var a = new Child { Name = "My Name is A" };
  var b = Test(a);
  Console.WriteLine(a.Name);
  Console.WriteLine(b.Name);
}

T Test<T>(T instance) where T : Base
{
  var instanceNew = Activator.CreateInstance<T>();
  instanceNew.Name = "Sucess";
  return instanceNew;
}

因为使用了classes,所以可以简化为:

T Test<T>(T instance) where T : Base, new()
{
  var instanceNew = new T();
  instanceNew.Name = "Sucess";
  return instanceNew;
}

但请注意,当将 object 作为祖先传递时,此通用解决方案不起作用 class:

var b = Test((Base)a);

将被处理为 Base 而不是 Child

所以我们可以将 non-generic 解决方案与通用行为混合来编写:

T Test<T>(T instance) where T : Base, new()
{
  var instanceNew = (T)Activator.CreateInstance(instance.GetType());
  instanceNew.Name = "Sucess";
  return instanceNew;
}

因此现在效果更好并且更一致:

Base a = new Child { Name = "My Name is A" };
Child b = (Child)Test(a);
Console.WriteLine(a.Name);
Console.WriteLine(b.Name);

输出

My Name is A
Sucess

可能的简化

除非你想在Test方法中做特定的处理,在参数的真实类型上,对于一个新的实例,只知道这个参数是Base的类型,以能够传递任何 child,然后 return 它,例如重构一些东西,你可以直接写:

var a = new Child { Name = "My Name is A" };

var b = (Child)Activator.CreateInstance(a.GetType());

b.Name = "Success";

注意:请不要使用base作为变量名,因为它是保留语言关键字,所以不会编译 - 另外,这是一个意见,避免使用 @base 因为它不干净,事实上它可能是问题和混乱的根源。