在 C++/CLI 中,如何声明和调用带有“out”参数的函数?

In C++/CLI, how do I declare and call a function with an 'out' parameter?

提问人:Simon 提问时间:10/9/2008 最后编辑:Ben VoigtSimon 更新时间:5/13/2014 访问量:49570

问:

我有一个函数,可以将一个字符串解析为两个字符串。在 C# 中,我会这样声明它:

void ParseQuery(string toParse, out string search, out string sort)
{
    ...
}

我会这样称呼它:

string searchOutput, sortOutput;
ParseQuery(userInput, out searchOutput, out sortOutput);

当前项目必须在 C++/CLI 中完成。我试过了

using System::Runtime::InteropServices;

...

void ParseQuery(String ^ toParse, [Out] String^ search, [Out] String^ sort)
{
    ...
}

但如果我这样称呼它:

String ^ searchOutput, ^ sortOutput;
ParseQuery(userInput, [Out] searchOutput, [Out] sortOutput);

我收到一个编译器错误,如果我这样调用它:

String ^ searchOutput, ^ sortOutput;
ParseQuery(userInput, searchOutput, sortOutput);

然后我在运行时收到错误。我应该如何声明和调用我的函数?

.NET C++-CLI 按引用传递

评论

0赞 teeks99 2/22/2017
我认为这应该代替.using namespace System::Runtime::InteropServices;using System::Runtime::InteropServices;

答:

-2赞 Greg Dean 10/9/2008 #1

它不受支持。你能得到的最接近的是 ref

当然,您可以伪造它,但您会丢失编译时间检查。

评论

0赞 Simon 10/9/2008
还行。。。如何在托管 C++ 中声明和调用带有 ref 参数的函数?
1赞 Greg Dean 10/10/2008
不知道为什么这被否决了。实际上它不受支持。当然,您可以伪造它,但您会丢失编译时间检查。这是一件大事 imo
0赞 2/27/2014
C++/CLI 可以调用 C# 参数,将它们视为参数。差异似乎仅在调用端(C++ 定义与 C# 定义相同,后者仍然指定并且两者都应限制 C# 调用)outrefout
0赞 Alexander Pacha 4/29/2014
有可能...请参阅上面的答案。你不会再失去任何东西了,所以你可以删除这篇文章。
92赞 Bert Huijben 10/9/2008 #2

C++/CLI 本身不支持真正的“out”参数,但您可以将引用标记为 out 参数,以使其他语言将其视为真正的 out 参数。

您可以对以下引用类型执行此操作:

void ReturnString([Out] String^% value)
{
   value = "Returned via out parameter";
}

// Called as
String^ result;
ReturnString(result);

对于以下值类型:

void ReturnInt([Out] int% value)
{
   value = 32;
}

// Called as
int result;
ReturnInt(result);

% 使其成为“ref”参数,OutAttribute 标记它仅用于输出值。

评论

1赞 Greg Dean 10/10/2008
我不认为这与 C# out 修饰符不同。例如,在 C# 中,如果它标记出且未分配给某个参数,则会导致编译器错误。这在您的示例中是一样的吗?
1赞 Bert Huijben 10/10/2008
这是 C# out 参数在 IL 级别上实现的方式:只有一个 ref 调用约定,用于 C# 中的 ref 和 out。带有 OutAttribute 的注释使其成为 out 参数。
1赞 Greg Dean 10/10/2008
IL 可能相同,但从语言的角度来看,C++ 不支持与 C# out 修饰符相同的东西。同样,它不支持 using() 语句的概念(您使用 try/finally 创建相同的 IL,但您失去了所有开发优势)。
3赞 Bert Huijben 10/10/2008
您可以通过在变量定义上不使用 ^ 来轻松重现。MC++ 自动调用 IDisposable。当变量超出范围时释放。(如果您将变量传递给方法,则只需使用 . 而不是 -> 和 %variable )
11赞 Alexander Pacha 4/29/2014
不要忘记在头文件中,否则编译器找不到 Out-Attribute。using namespace System::Runtime::InteropServices;
10赞 Art Beall 5/26/2010 #3

使用 Visual Studio 2008,这工作并解决了我工作中的一个主要问题。谢谢!

// header
// Use namespace for Out-attribute.
using namespace System::Runtime::InteropServices; 
namespace VHT_QMCLInterface {
   public ref class Client
   {
    public:
        Client();
        void ReturnInteger( int a, int b, [Out]int %c);
        void ReturnString( int a, int b, [Out]String^ %c);
   }
}

// cpp
namespace VHT_QMCLInterface {

    Client::Client()
    {

    }

    void Client::ReturnInteger( int a, int b, [Out]int %c)
    {
        c = a + b;
    }
    void Client::ReturnString( int a, int b, [Out]String^ %c)
    {
        c = String::Format( "{0}", a + b);
    }
}

// cs
namespace TestQMCLInterface
{
    class Program
    {
        VHT_QMCLInterface.Client m_Client = new VHT_QMCLInterface.Client();
        static void Main(string[] args)
        {
            Program l_Program = new Program();
            l_Program.DoReturnInt();
            l_Program.DoReturnString();
            Console.ReadKey();
        }

        void DoReturnInt()
        {
            int x = 10;
            int y = 20;
            int z = 0;
            m_Client.ReturnInteger( x, y, out z);
            Console.WriteLine("\nReturnInteger: {0} + {1} = {2}", x, y, z);
        }

        void DoReturnString()
        {
            int x = 10;
            int y = 20;
            String z = "xxxx";
            m_Client.ReturnString(x, y, out z);
            Console.WriteLine("\nReturnString: {0} + {1} = '{2}'", x, y, z);
        }
     }
}