如何创建一个新的 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
因为它不干净,事实上它可能是问题和混乱的根源。
如何在 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
因为它不干净,事实上它可能是问题和混乱的根源。