c# - 实现一个非泛型的静态工厂方法以从字符串输入创建各种泛型类(不使用 "dynamic"类型)

标签 c# factory builder strong-typing

我有一组从解析的 XML 定义和填充的类。
作为其中的一部分,我希望能够动态实例化特定类型的集合类,如 XML 指定的那样(在本例中,用于管理/实例化异常)。
所以我有一个类,大致定义如下:

public class ExceptionGroup<T> : BaseCollectionClass<Exception> where T : Exception 
{
    // contents of this class don't really matter
}
当我处理 XML 时,我将在字符串中包含异常派生类型的名称(即“ArgumentNullException”、“InvalidDataException”、“IndexOutOfRangeException”等),以及将使用的内容(消息)当/如果它被抛出时填充生成的异常(也是一个字符串)。
所以,为了到达我想要去的地方,我首先实现了几个相关的静态类(在别处定义):
// Recursively determines if a supplied Type is ultimately derived from the Exception class:
public static bool IsException( Type type ) =>
    (type == typeof( object )) ? false : (type == typeof(Exception)) || IsException( type.BaseType );

// Figures out if the specified string contains the name of a recognized Type 
// and that the Type itself is genuinely derived from the Exception base class:
public static Type DeriveType( string name )
{
    // If the string is null, empty, whitespace, or malformed, it's not valid and we ignore it...
    if ( !string.IsNullOrWhiteSpace( name ) && Regex.IsMatch( name, @"^([a-z][\w]*[a-z0-9])$", RegexOptions.IgnoreCase ) )
        try
        {
            Type excType = System.Type.GetType( name );
            if ( IsException( excType ) ) return excType;
        }
        catch { }

    // The type could not be determined, return null:
    return null; 
}
使用这些类,我可以获取一个输入字符串,并最终得到一个从 Exception 类派生的已知、现有的 C# Type 类(假设输入字符串是有效的)。现在我想构建一个可以创建新的工厂方法 ExceptionGroup<T>对象,其中“T”是从原始字符串派生的对象类型。
我已经通过使用 dynamic 来解决这个问题。 type 作为工厂的返回类型如下:
public static dynamic CreateExceptionGroup( string exceptionTypeName )
{
    Type excType = DeriveType( exceptionTypeName );
    if ( !(excType is null) )
    {
        Type groupType = typeof( ExceptionGroup<> ).MakeGenericType( new Type[] { excType } );
        return Activator.CreateInstance( groupType );
    }
    return null;
}
不过,我对此感到非常不舒服,既因为我不喜欢结果的模棱两可/不确定性,又因为随后处理该结果可能会更加麻烦/复杂。我宁愿更具体地指定返回类型,然后以某种方式适本地转换/限定它,例如(是的,我知道这是无效的!):
public static ExceptionGroup<> CreateGroup( string exceptionTypeName )
{
    Type excType = DeriveType( exceptionTypeName );
    if ( !(excType is null) )
    {
        Type[] types = new Type[] { excType };
        Type groupType = typeof( ExceptionGroup<> ).MakeGenericType( types );
        return (ExceptionGroup<>)Activator.CreateInstance( groupType );
    }
    return null;
}
...但是,当然 ExceptionGroup<>在此语法/上下文中无效。 (生成“CS7003: Unexpected use of an unbound generic name”),也不是仅仅使用 ExceptionGroup (生成:“CS0305:使用泛型类型 'ExceptionGroup' 需要 1 个类型参数。”)
那么,有没有办法通过一些其他的语法或机制,通过更精确的结果来使用强(er)类型,或者正在使用 dynamic ,以及所有后续相关的开销,实际上是实现此目的的唯一方法吗?

最佳答案

虽然我希望可能有一个更简单/简洁的解决方案(如果有的话,我很乐意看到它!)Sweeper 的一些回顾性提示让我意识到我可以通过注入(inject)一个新的抽象祖先的开销来基本上绕过这个问题类(class):

public abstract class ExceptionGroupFoundation : BaseCollectionClass<Exception>
{
    public ExceptionGroupFoundation( object[] args = null ) : base( args ) { }

    // Implement necessary common accessors, methods, fields, properties etc here...
    // (preferably "abstract" as/when/where possible)
}
...然后从那个派生我的通用类:
public class ExceptionGroup<T> : ExceptionGroupFoundation where T : Exception 
{
    public ExceptionGroup( object[] args = null ) : base( args ) { }

    // contents of this class don't really matter
}
...然后使用新的抽象类作为返回类型声明我的工厂方法:
public static ExceptionGroupFoundation CreateGroup( string exceptionTypeName )
{
    Type excType = DeriveType( exceptionTypeName );
    if ( !(excType is null) )
    {
        Type[] types = new Type[] { excType };
        Type groupType = typeof( ExceptionGroup<> ).MakeGenericType( types );
        return (ExceptionGroupFoundation)Activator.CreateInstance( groupType );
    }
    return null;
}
...基本上达到预期的结果,尽管有些麻烦/尴尬。

关于c# - 实现一个非泛型的静态工厂方法以从字符串输入创建各种泛型类(不使用 "dynamic"类型),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65376383/

相关文章:

c# - 以异步方式启动任务的其他方式

c# - 将 int.TryParse 与可为空的 int 一起使用

c# - DELETE 命令超时

c# - 是否可以将 c# 对象初始值设定项与工厂方法一起使用?

java - 构建者的消费者或函数

c# - 如何读取超过 65535 行的 Excel 2007 电子表格?

java - 多态数组类规则(超市程序)

c# - 自定义 'ExportFactory'

java - "Redraw"LinearLayout View 更改选项

caching - 将环境状态显式附加到 SCons Builder 依赖项 MD5 指纹