显式调用的 C# 构造函数歧义 - 错误 CS0012

C# Constructors Ambiguity with explicit call - Error CS0012

C# 中存在无法解释的歧义,我在其中明确尝试调用构造函数,但编译器认为它是不同的构造函数。我将从展示我们使用的简短 C# 架构开始。然后展示我创建的一个小的“工作”示例,以及对此的可能解决方案,但我仍然想了解为什么会发生这种情况。

架构:

  1. 连接 C++ 的 CLR DLL API。
  2. C#API使用桥接级别
  3. 使用 C# API.
  4. 的 C# 客户端应用程序

我创建的例子

CLR DLL 中的 class:

#pragma once

#include <string>

using namespace System;

namespace Inner {
    public ref class AInner
    {
    public:

        AInner() : _data(new std::wstring(L"")) {}

        ~AInner() {
            delete _data;
        }

        property String^ Val
        {
            String^ get()
            {
                return gcnew String((*_data).data());
            }

            void set(String^ value) {
                System::IntPtr pVal = System::Runtime::InteropServices::Marshal::StringToHGlobalUni(value);
                *_data = (const wchar_t*)pVal.ToPointer();
                System::Runtime::InteropServices::Marshal::FreeHGlobal(pVal);
            }
        }

    private:

        std::wstring* _data;
    };
}

Class 在 DLL 中包装 CLR 级别:

using System;

using Inner;

namespace Outer
{
    public class A
    {
        public A()
        {
            _inner.Val = String.Empty;
        }

        public A(string val)
        {
            init(val);
        }

        public string Val
        {
            get
            {
                return _inner.Val;
            }
            set
            {
                _inner.Val = value;
            }
        }

        internal A(AInner inner)
        {
            _inner = inner;
        }

        private void init(string Val)
        {
            _inner = new AInner();
            _inner.Val = String.Empty;
        }

        private AInner _inner;
    }
}

请注意,有一个 internal 构造函数和一个 public 构造函数。

使用 C# API DLL 的可执行客户端:

using Outer;

namespace OneClient
{
    class Program
    {
        static void Main(string[] args)
        {
            string myString = "Some String";
            A testA = new A(myString);
        }
    }
}

故事转折:

在包裹CLR层级的DLL中,不是ALL API应该被外部客户端使用,而是可以被内部客户端使用,因此通过添加[=15=将内部暴露给内部客户端] 到包装 CLR 级别的 DLL 的 'AssemblyInfo.cs'。

问题

编译客户端代码时出现以下错误: error CS0012: The type 'AInner' is defined in an assembly that is not referenced. You must add a reference to assembly 'InnerOne, Version=1.0.7600.28169, Culture=neutral, PublicKeyToken=null'.

  1. 我无法使用InnerOne,因为不允许客户使用此级别。
  2. 客户端同时暴露给 A(string val)A(AInner inner) 构造函数。

可能的解决方法:

  1. 删除 [assembly: InternalsVisibleTo("OneClient")] - 由于特定客户端需要使用的其他 classes 内部结构,这是不可接受的。
  2. A(string val) 构造函数更改为 A(string val, bool unique=true) 并使用它 A testA = new A(myString, true) - 不是一个好的解决方案。
  3. 使用默认构造函数 A() 并调用 testA.Val = myString; - 这实际上没问题,但代码太多。
  4. 将客户端代码从 A testA = new A(myString) 更改为 A testA = new A(val:myString); - 这实际上是选择的解决方案。

问题

为什么会出现这种歧义?

这是 Microsoft 编译器中的错误吗?

示例来源: 源代码 One.zip

我看不出这有什么问题,问题是我们习惯于以 wrong/briefly 的方式做事。

正确答案是:

A testA = new A(val:myString);

此外,您的所有调用(在这种方式下是对 constructor/initializer 的调用,但无论如何它都是一个调用)都应该带有参数名称。没有人(甚至我)写过它们,但是...

Why does this ambiguity happen?

因为为了满足构造函数重载决议,编译器需要知道所有的参数类型是什么,而不知道AInner是什么。

为什么不将 AInner 版本公开为工厂方法:

static internal A Create(AInner inner)
{
    return new A { _inner = inner };
}