Is there a replacement? If there is, how would the directive look for a file named "class.cs"? I just want to split the code into a file for each class.
The idiomatic way to achieve metaprogramming in C# (beyond Generics) is with T4 templates - Visual Studio and MSBuild supports T4 built-in, however VS does not come with T4 syntax coloring - you'll need a third-party add-in for that.
In order to demonstrate T4's include
functionality, I'll use the scenario of wanting to add an ==
operator overload to multiple classes simultaneously without using inheritance.
For comparison, in C++ it would be like this:
bool operator==(const TYPE* lhs, const TYPE* rhs) { if( lhs == nullptr && rhs != nullptr ) return false; return lhs.Equals(rhs); }
class Foo {
public:
#define TYPE Foo
#include "OperatorEquals.inc"
}
class Bar {
public:
#define TYPE Bar
#include "OperatorEquals.inc"
}
In C#, you would do this:
partial
classes so that all of your non-metaprogramming logic (i.e. normal C# code) is in a file, e.g. Foo.cs
and Bar.cs
.cs
partial class
definition of the same type within that T4 (*.tt
) file, though you won't have C# syntax highlighting.public static operator==(<#= typeName #> x, <#= typeName #> y) {
if( x == null && y != null ) return false;
return x.Equals( y );
}
<#@ 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" #>
}
Whenever you "Save" the .tt
file (even if you make no changes) VS will regenerate the output .cs
file which will look like this:
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 );
}
}
Note that this scenario is contrived - if you really did want to add the operator==
(and all the others: IEquatable<T>
, operator!=
, IComparable<T>
, etc) then you would probably use a T4 render function instead of an include, because that makes parameterization more straightforward and keeps everything self-contained in a single file:
<#@ 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
#>
No, there is no replacement for an #include statement. C# is an object-oriented language where code is organised into classes. You can use code from one class in another class depending on its visibility, and you can split the code from a single class across multiple source files using partial classes. These are essentially the way you use code from one "file" in another. But it's not the same thing at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With