AntSK 0.2.1 版本揭秘:動態載入dll,驅動Function Call新境界!

许泽宇發表於2024-03-16

在.NET的無限宇宙中,動態載入dll似乎一直是操控程式碼生生不息的魔杖。今天,我將與您探討如何透過AntSK 0.2.1 版本靈活運用dll,將Function Call的強大功能插拔自如地融入專案之中,我們走入外掛化開發的全新篇章。

新版本簡介

AntSK,這個曾被我們廣泛探討過的Semantic Kernel專案,這次再度帶來驚喜。在早先版本我們已經見識了其實現Function Call的威力。今日,我們有幸見證其升級再進化,0.2.1 版本究竟有何過人之處?答案就是:“動態載入dll”,這一核心玄機助您將程式碼實現外掛化,不再拘泥於單一的AntSK平臺編寫,帶來更加靈活的擴充套件性。

核心程式設計揭秘

要想細緻品味動態載入dll的精妙,首先要解開的鎖就是“約定”。AntSK要求外掛明晰其身份,一段標明“AntSK”特性的程式碼如同通行證,使得函式得以插入AntSK的世界。

public class TestFunctionImport
{
    /// <summary>
    /// 獲取名稱
    /// </summary>
    /// <returns>返回名稱</returns>
    [Description("AntSK")]
    public string GetName()
    {
        return $"""
               我的名字是AntSK,
               我的作者是許澤宇
               我是一個AI 知識庫/智慧體專案
            """;
    }
}

接下來,動態載入這塊寶藏怎能輕易讓人得逞?我們需要透過AssemblyLoadContext這位嚴厲的守門人,建立一個隔離的上下文,一步步引領我們:

var loadContext = new AssemblyLoadContext("AntSKLoadContext", true);
public void FuncLoad(string pluginPath)
{
    try
    {
        if (File.Exists(pluginPath))
        {
            string directory = Path.GetDirectoryName(pluginPath);
            string fileName = Path.GetFileName(pluginPath);
            var resolver = new AssemblyDependencyResolver(directory);

            // Create a custom AssemblyLoadContext

            loadContext.Resolving += (context, assemblyName) =>
            {
                string assemblyPath = resolver.ResolveAssemblyToPath(assemblyName);
                if (assemblyPath != null)
                {
                    return context.LoadFromAssemblyPath(assemblyPath);
                }
                return null;
            };
            // Load your assembly
            Assembly pluginAssembly = loadContext.LoadFromAssemblyPath(pluginPath);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message + " ---- " + ex.StackTrace);
    }
}

我們是如何評判“AntSK外掛”芳容?以下搜尋被特性標記的方法:

publicvoid SearchMarkedMethods()
{
   var markedMethods = new List<MethodInfo>();

   _methodCache.Clear();
   _methodInfos.Clear();

   foreach (var assembly in _assemblies)
   {
       // 從快取中獲取標記了ActionAttribute的方法
       foreach (var type in assembly.GetTypes())
       {
           markedMethods.AddRange(type.GetMethods().Where(m =>
           {
               DescriptionAttribute da = (DescriptionAttribute)m.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();
               return da != null && da.Description == "AntSK";
           }));
       }
   }

   //動態載入部分
   var loadedAssemblies = loadContext.Assemblies.ToList();
   foreach (var assembly in loadedAssemblies)
   {
       // 從快取中獲取標記了ActionAttribute的方法
       foreach (var type in assembly.GetTypes())
       {
           markedMethods.AddRange(type.GetMethods().Where(m =>
           {
               DescriptionAttribute da = (DescriptionAttribute)m.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();
               return da != null && da.Description == "AntSK";
           }));
       }
   }

   // 構建方法呼叫
   foreach (var method in markedMethods)
   {
       var key = $"{method.DeclaringType.Assembly.GetName().Name}_{method.DeclaringType.Name}_{method.Name}";
       string pattern = "[^a-zA-Z0-9_]";
       // 使用 '-' 替換非ASCII的正規表示式的字元
       key = Regex.Replace(key, pattern, "_");
       _methodCache.TryAdd(key, method);

       var xmlCommentHelper = new XmlCommentHelper();
       xmlCommentHelper.LoadAll();

       var description = xmlCommentHelper.GetMethodComment(method);
       var dict = xmlCommentHelper.GetParameterComments(method);

       var parameters = method.GetParameters().Select(x => (x.Name, x.ParameterType, dict[x.Name])).ToArray();
       var returnType = xmlCommentHelper.GetMethodReturnComment(method);

       if (string.IsNullOrEmpty(description))
       {
           description = "匯入外掛";
       }
       _methodInfos.TryAdd(key, (description, (method.ReflectedType, returnType), parameters));
   }
}

  

技術深度解讀

動態載入dll的涵義遠不止於表面的靈活,它開闢了無需重啟應用程式即可更新程式功能的可能。透過以上技巧,我們能夠在程式碼執行時插入或移除功能模組,極大地提升了程式碼的模組化和可維護性。

結語

搭上.Net技術的快車,我們彷彿有了橫穿時空的能力。AntSK 0.2.1版本正是這趟快車上一顆燦爛的星子,動態載入,外掛化程式設計,讓Function Call這一古老而又強大的術語,獲得了新的生命力。而今日的揭秘之旅,不知是否已讓您心潮澎湃,躍躍欲試?

別忘了,每一段程式碼都飽含著程式設計師的智慧與汗水,它們值得我們去細細玩味和傳唱。如果想要了解更多.Net技術,別忘了關注我的公眾號,後續還有更多精彩內容等待著你來探索。向著程式碼的化簡難度,以及程式設計模組化的美好未來,我們攜手同行,共同進步!

福利補充

為了讓您更好地理解AntSK的外掛化魔法,公眾號下期將提供詳細程式碼教程及其運用案例,敬請期待!別讓知識止步於此,讓我們在共享知識的海洋中,盡情航行吧!

相關文章