11 三月 2024
让我们来讨论一下我们的翻译器是如何将 C# 语言的语法结构转换为 C++ 语言的。我们将探讨翻译的具体细节以及在此过程中出现的限制。
翻译是基于每个项目进行的。一个C#项目被转换成一个或两个C++项目。第一个项目是C#项目的镜像,而第二个项目如果在原始项目中存在测试,则作为googletest应用程序来运行测试。每个输入项目都会生成一个CMakeLists.txt文件,允许为大多数构建系统创建项目。
通常,一个.cs文件对应一个.h文件和一个.cpp文件。通常,类型定义放在头文件中,而方法定义位于源代码文件中。但是,对于模板类型,所有代码都保留在头文件中。包含至少一个公共定义的头文件最终会出现在include目录中,可供依赖项目和最终用户访问。仅包含内部定义的头文件进入source目录。
除了从原始C#代码翻译得到的代码文件外,翻译器还生成包含服务代码的附加文件。配置文件中的条目指定在头文件中从哪里找到该项目的类型,也放在输出目录中。这些信息对于处理依赖的程序集是必要的。此外,一个全面的翻译日志存储在输出目录中。
using <typename> = ...
翻译。enum class
语法)。System::MulticastDelegate
类特殊化的别名:public delegate int IntIntDlg(int n);
using IntIntDlg = System::MulticastDelegate<int32_t(int32_t)>;
System.Object
的隐式继承变为显式继承。所有这些因素共同造成了一些限制:
我们知道,严格模仿 C# 行为需要采用某种不同的方法。尽管如此,我们还是选择了这种逻辑,因为它使转换后库的应用程序接口与 C++ 范例更加接近。下面的示例说明了这些特性:
C# 代码
using System;
public class Base
{
public virtual void Foo1()
{ }
public void Bar()
{ }
}
public interface IFoo
{
void Foo1();
void Foo2();
void Foo3();
}
public interface IBar
{
void Bar();
}
public class Child : Base, IFoo, IBar
{
public void Foo2()
{ }
public virtual void Foo3()
{ }
public T Bazz<T>(object o) where T : class
{
if (o is T)
return (T)o;
else
return default(T);
}
}
C++ 头文件
#pragma once
#include <system/object_ext.h>
#include <system/exceptions.h>
#include <system/default.h>
#include <system/constraints.h>
class Base : public virtual System::Object
{
typedef Base ThisType;
typedef System::Object BaseType;
typedef ::System::BaseTypesInfo<BaseType> ThisTypeBaseTypesInfo;
RTTI_INFO_DECL();
public:
virtual void Foo1();
void Bar();
};
class IFoo : public virtual System::Object
{
typedef IFoo ThisType;
typedef System::Object BaseType;
typedef ::System::BaseTypesInfo<BaseType> ThisTypeBaseTypesInfo;
RTTI_INFO_DECL();
public:
virtual void Foo1() = 0;
virtual void Foo2() = 0;
virtual void Foo3() = 0;
};
class IBar : public virtual System::Object
{
typedef IBar ThisType;
typedef System::Object BaseType;
typedef ::System::BaseTypesInfo<BaseType> ThisTypeBaseTypesInfo;
RTTI_INFO_DECL();
public:
virtual void Bar() = 0;
};
class Child : public Base, public IFoo, public IBar
{
typedef Child ThisType;
typedef Base BaseType;
typedef IFoo BaseType1;
typedef IBar BaseType2;
typedef ::System::BaseTypesInfo<BaseType, BaseType1, BaseType2> ThisTypeBaseTypesInfo;
RTTI_INFO_DECL();
public:
void Foo1() override;
void Bar() override;
void Foo2() override;
void Foo3() override;
template <typename T>
T Bazz(System::SharedPtr<System::Object> o)
{
assert_is_cs_class(T);
if (System::ObjectExt::Is<T>(o))
{
return System::StaticCast<typename T::Pointee_>(o);
}
else
{
return System::Default<T>();
}
}
};
C++ 源代码
#include "Class1.h"
RTTI_INFO_IMPL_HASH(788057553u, ::Base, ThisTypeBaseTypesInfo);
void Base::Foo1()
{
}
void Base::Bar()
{
}
RTTI_INFO_IMPL_HASH(1733877629u, ::IFoo, ThisTypeBaseTypesInfo);
RTTI_INFO_IMPL_HASH(1699913226u, ::IBar, ThisTypeBaseTypesInfo);
RTTI_INFO_IMPL_HASH(3787596220u, ::Child, ThisTypeBaseTypesInfo);
void Child::Foo1()
{
Base::Foo1();
}
void Child::Bar()
{
Base::Bar();
}
void Child::Foo2()
{
}
void Child::Foo3()
{
}
每个翻译类开头的一系列别名和宏用于模拟某些 C# 机制,主要是 GetType
、typeof
和 is
。.cpp 文件中的哈希代码用于有效的类型比较。所有实现接口的函数都是虚拟的,尽管这与 C# 的行为不同。