C#中的#include指令
有替代品吗? 如果有,指令将如何查找名为“class.cs”的文件? 我只想将代码拆分为每个类的文件。
不,#include语句没有替代品。 C#是一种面向对象的语言,其中代码被组织成类。 您可以根据其可见性使用另一个类中的一个类的代码,并且可以使用分部类将代码从单个类拆分为多个源文件。 这些基本上就是你在另一个“文件”中使用代码的方式。 但它根本不是一回事。
在C#(超出generics)中实现元编程的惯用方法是使用T4模板 – Visual Studio和MSBuild支持T4内置,但是VS没有T4语法着色 – 你需要一个第三方加载项。
为了演示T4的include
function,我将使用想要在不使用inheritance的情况下同时向多个类添加==
运算符重载的场景。
为了比较,在C ++中它将是这样的:
OperatorEquals.inc
bool operator==(const TYPE* lhs, const TYPE* rhs) { if( lhs == nullptr && rhs != nullptr ) return false; return lhs.Equals(rhs); }
Code.h
class Foo { public: #define TYPE Foo #include "OperatorEquals.inc" } class Bar { public: #define TYPE Bar #include "OperatorEquals.inc" }
在C#中,你会这样做:
- 使用
partial
类,以便所有非元编程逻辑(即普通的C#代码)都在一个文件中,例如Foo.cs
和Bar.cs
- 在项目中创建一个新的T4模板,将输出文件扩展名更改为
.cs
- 在该T4(
*.tt
)文件中创建相同类型的第二个partial class
定义,但您不会使用C#语法突出显示。 - 定义包含的文件:
Operators.inc.cs.t4
public static operator==(<#= typeName #> x, <#= typeName #> y) { if( x == null && y != null ) return false; return x.Equals( y ); }
- 将其添加到您的T4模板:
Metaprogramming.tt
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ import namespace="System" #> <#@ output extension=".cs" #> <# String typeName = null; #> public partial class Foo { <# typeName = "Foo"; #> <#@ include file="Operators.inc.cs.t4" #> } public partial class Bar { <# typeName = "Bar"; #> <#@ include file="Operators.inc.cs.t4" #> }
每当你“保存” .tt
文件时(即使你没有做任何更改),VS将重新生成输出.cs
文件,如下所示:
public partial class Foo { public static operator==(Foo x, Foo y) { if( x == null && y != null ) return false; return x.Equals( y ); } } public partial class Bar { public static operator==(Bar x, Bar y) { if( x == null && y != null ) return false; return x.Equals( y ); } }
请注意,这种情况是设计的 – 如果你确实想要添加operator==
(以及所有其他operator==
: IEquatable
, operator!=
, IComparable
等),那么你可能会使用T4渲染函数代替包含,因为这使参数化更直接,并将所有内容保持在一个文件中:
T4RenderFunction.tt
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ import namespace="System" #> <#@ output extension=".cs" #> <# String typeName = null; #> public partial class Foo { <# RenderBoilerplateOperators("Foo"); #> } public partial class Bar { <# RenderBoilerplateOperators("Bar"); #> } <#+ // Functions are declared at the bottom void RenderBoilerplateOperators(String typeName) { #> public static operator==(<#= typeName #> lhs, <#= typeName #> rhs) { return <#= typeName #>.Equals( lhs, rhs ); } public override Boolean Equals(<#= typeName #> other) { return <#= typeName #>.Equals( this, other ); } public static Boolean Equals(<#= typeName #> lhs, <#= typeName #> rhs) { // T4 can use VS DTE to enumerate members of `typeName`, but you're probably better-off implementing this method manually } public static operator!=(<#= typeName #> lhs, <#= typeName #> rhs) { return !<#= typeName #>.Equals( lhs, rhs ); } // and so on... <# } // void RenderBoilerplateOperators #>
另外,不要忘记C# partial类具有一些您可能通过#include语句获得的function。
部分类允许您将类定义拆分为多个文件。
与C#中的C或C ++不同,不需要#include来使用其他文件中定义的类型。 相反,C#基于容器(如类或命名空间)进行类型解析。 只要两个文件都包含在编译中并且第二种类型的命名空间可用,那么您的类就可以访问。
例:
将Class1.cs
namespace Project1 { class Class1 { ... } }
Class2.cs
namespace Project1 { class Class2 { private Class1 m_field1; .. } }
有点不清楚你的意思。 但是你在考虑:
using MyNamespace;
查看使用声明
如果使用msbuild或在csc(C#Compiler)命令行中,则将每个文件包含在* .csproj中:
csc File1.cs File2.cs
http://msdn.microsoft.com/en-us/library/78f4aasd%28VS.80%29.aspx
它与C的#include指令不完全相同,但C#的using语句就是你所追求的:
using Assembly.Name;
它在命名空间级别而不是文件级别工作。 因此,如果class.cs
在Application.Core
命名空间中包含一个名为SomeClass
的公共类,则它看起来像:
using Application.Core;
这通常放在您正在使用的文件的顶部,并允许该类使用SomeClass
作为对象(以及Application.Core
命名空间中的所有其他公共类)。
当然,如果类都在同一个命名空间(例如Application.Core
),那么根本就没有理由使用using
语句。 同一名称空间中的类可以在没有任何声明的情况下相互解析。
您需要将class.cs的内容放入命名空间。 然后在需要查看class.cs的文件顶部放置一个using语句。
class.cs namespace Class { //class.cs stuff }
然后在需要类的文件中执行以下操作。
using Class;
使用Partial Class
的示例。
Main.cs
partial class Program { private static void Main() { A(); B(); } }
fileA.cs
partial class Program { private static void A() => Console.WriteLine("A"); }
fileB.cs
partial class Program { private static void B() => Console.WriteLine("B"); }