繁体   English   中英

实现非泛型 static 工厂方法以从字符串输入创建各种泛型类(不使用“动态”类型)

[英]Implement a non-generic, static Factory method to create various Generic Classes from string input (without using “dynamic” type)

我有一组从解析的 XML 定义和填充的类。

作为其中的一部分,我希望能够动态实例化特定类型的集合类,如 XML 指定的(在这种情况下,管理/实例化异常)。

所以我有一个class,大致定义如下:

public class ExceptionGroup<T> : BaseCollectionClass<Exception> where T : Exception 
{
    // contents of this class don't really matter
}

当我处理 XML 时,我将在字符串中包含异常派生类型的名称(即“ArgumentNullException”、“InvalidDataException”、“IndexOutOfRangeException”等),以及将使用的内容(消息)当/如果它被抛出时填充生成的异常(也是一个字符串)。

所以,为了得到我想要 go 的地方,我首先实现了几个相关的 static 类(在其他地方定义):

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

使用这些类,我可以获取一个输入字符串并最终得到一个已知的、现有的 C# 类型 class(假设输入字符串有效),它派生自异常 class。 现在我想构建一个工厂方法,可以创建新的ExceptionGroup<T>对象,其中“T”是从原始字符串派生的 object 类型。

我通过使用dynamic类型作为工厂的返回类型管理它,如下所示:

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:意外使用未绑定的通用名称”),也不是仅使用ExceptionGroup (生成:“CS0305:使用通用类型 'ExceptionGroup' 需要 1 种类型 arguments。”)

那么,没有办法通过某种其他语法或机制,通过更精确地描述结果,使用强(er)类型来做到这一点,或者使用dynamic ,以及所有后续相关的开销,实际上是实现这一目标的唯一方法?

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

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)
}

...然后从那个派生我的通用 class :

public class ExceptionGroup<T> : ExceptionGroupFoundation where T : Exception 
{
    public ExceptionGroup( object[] args = null ) : base( args ) { }

    // contents of this class don't really matter
}

...然后使用新的抽象 class 作为返回类型声明我的工厂方法:

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

...基本上达到预期的结果,尽管有些麻烦/尴尬。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM