簡體   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