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

同一命名空间下双模块DLL在C#中仅单模块可见的问题咨询

问题背景

我有一个F#类库项目,项目定义如下:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Library</OutputType>
    <TargetFramework>net7.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="Program.fs" />
    <Compile Include="Api.fs" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="OfficeIMO.Word" Version="0.11.0" />
  </ItemGroup>

</Project>

Program.fs包含docx命名空间下的WordProcessingML模块,Api.fs包含同一命名空间下的Api模块。项目可正常编译发布为DLL,但在C#项目中引用该DLL时,仅能看到WordProcessingML模块,Api模块不可见。

我的问题:

  1. 如何操作才能让C#项目使用Api模块?
  2. 当前做法存在什么问题?(我猜测DLL仅编译了第一个模块,未包含后续模块)

另外,我的代码组织遵循Scott Wlaschin的一份代码结构指南,想知道这份指南是否已经过时。

Api.fs代码如下:

// 遵循上述指南编写
namespace docx
module Api =
    type Run = docx.WordProcessingML.Run
    type DocumentPart = docx.WordProcessingML.DocumentPart
    let Save(document: docx.WordProcessingML.Document): string =
        if isNull (box document) then nullArg "document"
        docx.WordProcessingML.Save document
    let Paragraph(runs: Run seq): docx.WordProcessingML.Paragraph =
        if isNull (box runs) then nullArg "runs"
        List.ofSeq runs
    let Document(path: string, parts: DocumentPart seq): docx.WordProcessingML.Document =
        if isNull (box path) then nullArg "path"
        if isNull (box parts) then nullArg "parts"
        {path=path; parts=(List.ofSeq parts)}
    let IntoPart(paragraph: docx.WordProcessingML.Paragraph): Result<DocumentPart, string>=
        if isNull (box paragraph) then
            Error("Null Parameter")
        else
            Ok(docx.WordProcessingML.Par paragraph)
解答

问题1:让C#项目使用Api模块的操作方法

F#模块及模块内的let绑定函数默认是内部可见性(internal),外部程序集无法访问。要让C#项目能使用Api模块,需要修改两处:

  1. 给Api模块添加public修饰符,使其对外可见:
namespace docx
// 添加public修饰符
public module Api =
    // 原有代码保持不变
    type Run = docx.WordProcessingML.Run
    // ... 其余代码
  1. 给模块内需要被C#调用的函数添加公共可见性:
    • F# 5.0及以上版本可直接用public修饰符:
      public let Save(document: docx.WordProcessingML.Document): string =
          if isNull (box document) then nullArg "document"
          docx.WordProcessingML.Save document
      
    • 旧版本可使用[<Public>]属性:
      [<Public>]
      let Save(document: docx.WordProcessingML.Document): string =
          if isNull (box document) then nullArg "document"
          docx.WordProcessingML.Save document
      

修改后重新编译DLL,C#项目引用后即可访问docx.Api模块及其中的公共成员。

问题2:当前做法的问题

你的猜测错误,DLL实际上已经包含了Api模块,但模块和其中的函数默认是internal可见性,C#项目作为外部程序集无法访问内部成员,因此看不到Api模块。

F#与C#的默认可见性规则有差异:C#中类默认是internal,但类型成员默认是private;而F#的模块、let绑定函数默认都是internal,仅type定义的类型默认是public。这就是你能看到WordProcessingML里的类型,但看不到Api模块的核心原因。

关于代码结构指南的时效性

你参考的这份代码结构指南核心思想依然有效,它强调的F#项目编译顺序、命名空间与模块的组织方式,至今仍是F#项目的最佳实践之一。仅在语法细节上有微小更新:F# 5.0之后支持了更简洁的public修饰符(之前只能用[<Public>]属性),但整体结构思路并未过时。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:56:30