如何在AOT平台上在运行时生成任何通用类型?

4

我需要在AOT平台上运行时生成通用类型。我知道一种“解决方法”,它通过在代码中创建一个虚拟方法来提示编译器生成特定的通用类:

public void DoDummy(){
    var a1 = new MyClass<MyType>();
}

很遗憾,这种特定的解决方法对我并不适用,因为我有数十万个(没有夸张)可能创建的类型组合。

是否有任何方法可以实现我所尝试达到的目标?

2个回答

4

虽然并不是完美的解决方案,但我发现使用通用接口和通用抽象类比采用枚举所有组合(常规解决方法)要好得多。

创建一个通用类,例如:

public abstract class GenericBase<T>
{
    public static bool AOTConstruct()
    {
        bool b = (new GV<T>() == null); // Where GV<T> is a Generic Class.
        // Do similar for all Generic Classes that need to be AOT compiled.
        return b;
    }
}

然后创建一个通用接口,例如这样:
public interface IGenericValue<T>
{
    GenericBase<T> ConstructGenericBase();
}

现在,可以通过将系统类型声明为实现接口的类的类型,对AOTConstruct中列出的通用类进行AOT编译,示例如下:
public class SystemTypes : IGenericValue<float> // Implement IGenericValue for other Types.
{
    GenericBase<float> IGenericValue<float>.ConstructGenericBase()
    {
        throw new NotImplementedException();
    }
}

对于任何自定义类,都可以采取同样的方法进行操作,无论是在与系统类型相同的类中,还是作为自定义类声明的一部分(我更喜欢这种方式以提高清晰度)。

不得不更新SystemTypes以支持新的系统级别类型,并更新AOTConstruct以支持需要支持的新通用类,这令人失望,但它适用于编译到iOS,并不需要列出所有组合。


1
我知道这是一个较旧的问题和答案,但这里的好处是您可以在AOTConstruct中列出所有打开的泛型类型,将它们从由实现接口指定的类型参数中抽象出来。由于接口现在允许默认实现(而且ConstructGenericBase永远不会被调用),因此接口实现现在可以简化(除非我误解了什么)。您仍然需要明确列出每个泛型类型,但也许源代码生成器可以帮助解决这个问题? - monkey0506
是的,我认为(尚未亲自测试)为IGenericValue.ConstructGenericBase提供默认接口实现可以简化SystemTypes,使其仅实现接口的所有通用实现,而无需显式定义自己的ConstructGenericBase实现。这也可能可以通过源代码生成器完成,尽管我个人不知道如何做到这一点。 - Lucas Stertz
使用其他最近的C#功能,例如泛型属性,可能可以使泛型属性类具有ConstructGenericBase方法,而不是将其包含在接口中。然后,GenericBase<T>可以用满足所需泛型的属性进行装饰。这将把泛型类(列在AOTConstruct中)和它们的泛型参数(作为装饰属性的泛型参数)放在一起,以便更容易地维护。 - Lucas Stertz

0

我不确定我完全理解你想做什么,但也许这可以帮助你:

private static object Create(Type genericType, params Type[] genericArguments)
{
    Type genericClass = genericType.MakeGenericType(genericArguments);
    return Activator.CreateInstance(genericClass);
}

这个方法为您想要创建的genericType创建所有必需的泛型类型参数,并通过使用其无参构造函数创建结果类型的实例。

如果您有一个类似于

public class MyClass<T>
{
}

如果想要使用字符串作为类型参数来实例化它,可以这样调用:string
var myinstance = Create(typeof(MyClass<>), typeof(string));

请注意,如果您想有效地使用返回值(myinstance),您应该将其声明为dynamic

1
嗨René,感谢您的回答。这就是我正在做的事情,但问题在于,在AOT平台上,如果正在创建的泛型类型在程序中没有声明过,将会抛出ExecutionEngineException异常。例如,如果我使用MakeGenericType创建一个MyClass<string>,并且在我的代码中没有声明"MyClass<string>",它将无法工作。如果我在我发布在问题中的虚拟方法中添加"MyClass<string>",那么它将可以工作。 - Rafael
啊,好的,我不知道那个。我没有使用过AOT平台的经验。很抱歉我无法帮助你。 - René Vogt
@Rafael 我现在也遇到了同样的问题。你最终是如何解决的? - shtse8

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接