C# 中的参数化 System.Type 变量
Parameterized System.Type Variable in C#
我正在尝试在 C# 中创建一个工厂 class,其中 returns 对象是或扩展了某种基本类型。每次在工厂调用 getInstance()
时,我都需要实例化该类型的新实例,所以我真的只想接受并存储类型本身。在 Java 中,我使用 Class<? extends Base>
来保存 class 来创建,然后在其上调用 getInstance()
。
我了解如何在 C# 中使用 Activator class 从 System.Type
创建新对象,但我不确定的部分是对 class 类型的约束.我希望能够只接受属于或扩展基础 class 的类型。我意识到我可以更改工厂上的 setter 以接受基本类型的实际对象,然后从中检索类型,但我真的不想实例化整个对象只是为了检索 Type 变量。
下面是一个小例子 Java 程序只是为了演示我需要什么,以防我的问题不清楚。在 C# 中有什么方法可以做到这一点吗?
class Program {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Factory.setClass(Base.class);
Base b = Factory.getInstance();
b.Print();
Factory.setClass(Child.class);
b = Factory.getInstance();
b.Print();
}
}
class Factory {
private static Class<? extends Base> type;
// What I want to do in C#.
public static void setClass(Class<? extends Base> newType) {
type = newType;
}
// What I don't want to have to do in C#.
public static void setClassFromObject(Base newTypeObject) {
type = newTypeObject.getClass();
}
public static Base getInstance() throws InstantiationException, IllegalAccessException {
return type.newInstance();
}
}
class Base {
public void Print() {
System.out.println("Hello from base.");
}
}
class Child extends Base {
@Override
public void Print() {
System.out.println("Hello from child.");
}
}
我不知道如何在编译时强制执行此操作,但如果您对运行时检查没问题,您可以这样做:
class Factory
{
private static Type _type;
public static void SetClass(Type t)
{
if (!(typeof(Base)).IsAssignableFrom(t))
{
throw new ArgumentException("type does not extend Base", nameof(t));
}
_type = t;
}
public static Base GetInstance()
{
return (Base)Activator.CreateInstance(_type);
}
}
您可以使 "GetInstance" 方法动态化,这样当您设置 class 时,您也设置了方法。这样你就可以在运行时依赖泛型来获得正确的类型。它可能看起来像这样:
public class Factory
{
private static Func<Base> _getInstance;
//option if you want to pass in an instantiated value
public static void SetClass<T>(T newType) where T : Base, new()
{
_getInstance = () => new T();
}
//option if you just want to give it a type
public static void SetClass<T>() where T : Base, new()
{
_getInstance = () => new T();
}
public static Base GetInstance()
{
return _getInstance();
}
//you could just make GetInstance Generic as well, so you don't have to set the class first
public static Base GetInstance<T>() where T : Base, new()
{
return new T();
}
}
我正在尝试在 C# 中创建一个工厂 class,其中 returns 对象是或扩展了某种基本类型。每次在工厂调用 getInstance()
时,我都需要实例化该类型的新实例,所以我真的只想接受并存储类型本身。在 Java 中,我使用 Class<? extends Base>
来保存 class 来创建,然后在其上调用 getInstance()
。
我了解如何在 C# 中使用 Activator class 从 System.Type
创建新对象,但我不确定的部分是对 class 类型的约束.我希望能够只接受属于或扩展基础 class 的类型。我意识到我可以更改工厂上的 setter 以接受基本类型的实际对象,然后从中检索类型,但我真的不想实例化整个对象只是为了检索 Type 变量。
下面是一个小例子 Java 程序只是为了演示我需要什么,以防我的问题不清楚。在 C# 中有什么方法可以做到这一点吗?
class Program {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Factory.setClass(Base.class);
Base b = Factory.getInstance();
b.Print();
Factory.setClass(Child.class);
b = Factory.getInstance();
b.Print();
}
}
class Factory {
private static Class<? extends Base> type;
// What I want to do in C#.
public static void setClass(Class<? extends Base> newType) {
type = newType;
}
// What I don't want to have to do in C#.
public static void setClassFromObject(Base newTypeObject) {
type = newTypeObject.getClass();
}
public static Base getInstance() throws InstantiationException, IllegalAccessException {
return type.newInstance();
}
}
class Base {
public void Print() {
System.out.println("Hello from base.");
}
}
class Child extends Base {
@Override
public void Print() {
System.out.println("Hello from child.");
}
}
我不知道如何在编译时强制执行此操作,但如果您对运行时检查没问题,您可以这样做:
class Factory
{
private static Type _type;
public static void SetClass(Type t)
{
if (!(typeof(Base)).IsAssignableFrom(t))
{
throw new ArgumentException("type does not extend Base", nameof(t));
}
_type = t;
}
public static Base GetInstance()
{
return (Base)Activator.CreateInstance(_type);
}
}
您可以使 "GetInstance" 方法动态化,这样当您设置 class 时,您也设置了方法。这样你就可以在运行时依赖泛型来获得正确的类型。它可能看起来像这样:
public class Factory
{
private static Func<Base> _getInstance;
//option if you want to pass in an instantiated value
public static void SetClass<T>(T newType) where T : Base, new()
{
_getInstance = () => new T();
}
//option if you just want to give it a type
public static void SetClass<T>() where T : Base, new()
{
_getInstance = () => new T();
}
public static Base GetInstance()
{
return _getInstance();
}
//you could just make GetInstance Generic as well, so you don't have to set the class first
public static Base GetInstance<T>() where T : Base, new()
{
return new T();
}
}