如何通过只知道基类类型来创建与另一个实例相同类型的类的新对象实例? [英] How to create a new object instance of class being the same type of another instance by only knowing it as base class type?

查看:37
本文介绍了如何通过只知道基类类型来创建与另一个实例相同类型的类的新对象实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How to dynamic down casting in C#?

我有以下这些类:

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 方法.

我想让它成为动态子类类型(A、B、C),而不是基础"类型.

I want to make it dynamic child class type(A, B, C), not "Base" type.

这样任何子类都可以工作.

So that any child class can work.

如何让 testA 动态地拥有数据类型?

How do I make testA have a datatype dynamically?

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";
    }
}

推荐答案

向下转换 在 C# 中是不可能的.

Downcasting is not possible in C#.

基础对象小于子对象,因此您不能创建基础对象并将其转换为子对象.

A base object is less than a child object, so you cannot create a base object and cast it to a child.

子对象中添加的属性和方法中缺少基类,因此您无法创建基对象并将其转换为子对象.

A base class is missing from the properties and methods added in childs, so you cannot create a base object and convert it to be a child object.

沙发可以是坐的椅子,但椅子不能是躺的沙发.

A sofa can be a chair to sit on it, but a chair can not be a sofa to lie down.

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

But upcasting is OOP fundamental: we can say that child is type of base.

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

Here you don't want to up or down cast, but create a new instance as formulated in the suggested new title for the question.

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

So to create another instance of the real base object type and not a base you can use reflexion and 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;
}

因为使用类,所以可以简化:

Because using classes, it can be simplified:

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

但请注意,当将对象作为祖先类传递时,这种通用解决方案不起作用:

But be carefull that this generic solution does not work when passing an object as an ancestor class:

var b = Test((Base)a);

将作为 Base 而不是 Child 处理.

Will be processed as Base and not Child.

因此我们可以将非泛型解决方案与泛型行为混合起来编写:

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

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

Thus that works better now and it is more consistent:

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,为了能够传递任何孩子,然后返回它,例如重构一些东西,你可以直接写:

Unless you want to do a particular processing in the Test method, on the real type of the parameter, for a new instance by only knowing this parameter as a type of Base, to be able to pass any child, and then return it, to refactor some things for example, you can direclty write:

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

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

b.Name = "Success";

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

Note: please, don't use base as a variable name because it is a reserved language keyword, so it does not compile - also, it is an opinion, avoid the use of @base because it is not clean, and in fact it can be source of problems and confusions.

这篇关于如何通过只知道基类类型来创建与另一个实例相同类型的类的新对象实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆