You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Delphi的.NET Runtime Library读取Assembly DLL的AssemblyID及解决相关问题

获取程序集Assembly ID(GUID)的问题与解决方法

问题描述

  • 需求:创建函数直接从Assembly DLL读取AssemblyID,用于通用注册程序集,调用方式为:
    TClrAssembly.RegisterDLLAssembly(AssemblyGuid, AssemblyLocation, ltfileLocation); 
    
  • 当前方案问题:部分DLL的CustomAttributesData列表中缺少GuidAttribute,部分存在该属性但内容与预期GUID不符。
  • 当前代码:
    function GUIDFromAssembly(AssemblyFileName: string): string;
    var
      InspectedAssembly: _Assembly;
      GenericList: _GenericIList;
      GenericItems: _GenericICollection;
    begin
      result := '';
      InspectedAssembly:= CoAssemblyHelper.CreateInstance.ReflectionOnlyLoadFrom(AssemblyFileName); 
      if not assigned(InspectedAssembly) then
        raise Exception.CreateFmt('Assembly %s not found', [AssemblyFileName]);
    
      GenericList := InspectedAssembly.GetCustomAttributesData;
      GenericItems := GenericList.AsGenericICollection;
      for c := 0 to GenericItems.Count - 1 do 
      begin
        s := GenericList.Item[c].ToString;
        Log(c.ToString + ': ' + s);
        if s.StartsWith('[System.Runtime.InteropServices.GuidAttribute("') then
          result := s.Substring(47, 36);
      end;
    end;   
    
  • 额外疑问:_GenericIList为何没有Length属性?通过AsGenericICollection遍历的方式是否正确?

解决方案

正确获取Assembly GUID的方式

你当前通过解析CustomAttributesData字符串的方式不可靠,原因有两点:一是并非所有程序集都会显式标记GuidAttribute;二是字符串解析容易因格式变动出错。

推荐两种更可靠的实现方式:

方式1:直接读取程序集的Guid属性

function GUIDFromAssembly(AssemblyFileName: string): string;
var
  InspectedAssembly: _Assembly;
  GuidValue: TGUID;
begin
  Result := '';
  InspectedAssembly := CoAssemblyHelper.CreateInstance.ReflectionOnlyLoadFrom(AssemblyFileName);
  if not Assigned(InspectedAssembly) then
    raise Exception.CreateFmt('Assembly %s not found', [AssemblyFileName]);

  // 直接获取程序集内置的Guid
  if Succeeded(InspectedAssembly.GetGuid(GuidValue)) then
    Result := GUIDToString(GuidValue);
end;

方式2:通过AssemblyName获取

如果方式1无法使用,可通过程序集名称对象读取Guid:

function GUIDFromAssembly(AssemblyFileName: string): string;
var
  AssemblyName: _AssemblyName;
  GuidValue: TGUID;
begin
  Result := '';
  AssemblyName := CoAssemblyName.CreateInstance;
  AssemblyName.InitFromFile(AssemblyFileName);
  
  if Succeeded(AssemblyName.GetGuid(GuidValue)) then
    Result := GUIDToString(GuidValue);
end;

关于_GenericIList的疑问解答

  • 为何没有Length属性:.NET原生的IList<T>接口定义的是Count属性而非Length,Length一般用于数组类型。你使用的_GenericIList是COM互操作映射后的接口,遵循原.NET接口规范,因此只有Count属性。
  • AsGenericICollection遍历是否正确:这种方式可行,但没必要——直接利用_GenericIList自身的Count属性遍历更高效,无需转换为_GenericICollection:
    GenericList := InspectedAssembly.GetCustomAttributesData;
    for c := 0 to GenericList.Count - 1 do 
    begin
      // 处理逻辑
    end;
    
    转换为_GenericICollection主要是为了使用ICollection接口的Add、Remove等修改类方法,单纯遍历的话直接用_GenericIList即可。

内容的提问来源于stack exchange,提问作者user20518651

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 18:31:02