Директива #include в С#

Есть ли замена? Если есть, как бы директива искала файл с именем "class.cs"? Я просто хочу разбить код на файл для каждого класса.

Ответ 1

Нет, нет замены для оператора #include. С# - объектно-ориентированный язык, где код организован в классы. Вы можете использовать код из одного класса в другом классе в зависимости от его видимости, и вы можете разделить код из одного класса на несколько исходных файлов с помощью частичных классов. Это по сути то, как вы используете код из одного "файла" в другом. Но это не то же самое.

Ответ 2

Идиоматический способ достижения метапрограммирования в С# (помимо Generics) - с шаблонами T4 - Visual Studio и MSBuild поддерживает T4 встроенный, однако VS не поставляется с синтаксической раскраской T4 - вам понадобится сторонний add- для этого.

Чтобы продемонстрировать функциональность T4 include, я буду использовать сценарий, требующий добавить перегрузку оператора == к нескольким классам одновременно без использования наследования.

Для сравнения, в С++ это будет так:

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"
}

В С# вы сделаете следующее:

  • Используйте классы partial, чтобы вся ваша логика без метапрограммирования (то есть нормальный код С#) находилась в файле, например. Foo.cs и Bar.cs
  • Создайте новый шаблон T4 в своем проекте, измените расширение выходного файла на .cs
  • Создайте второе определение partial class того же типа в этом файле T4 (*.tt), хотя вы не будете выделять синтаксис С#.
  • Определите включенный файл:

Operators.inc.cs.t4

public static operator==(<#= typeName #> x, <#= typeName #> y) {
    if( x == null && y != null ) return false;
    return x.Equals( y );
}
  1. Добавьте его в свой шаблон 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== (и все остальные: IEquatable<T>, operator!=, IComparable<T> и т.д.), то вы, вероятно, используете функцию рендеринга T4 вместо include, потому что это делает параметризацию более простой и сохраняет все самодостаточным в одном файле:

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
#>

Ответ 3

В отличие от C или С++ в С# нет необходимости использовать #include для использования типов, определенных в других файлах. С# вместо этого создает разрешение на основе таких контейнеров, как классы или пространства имен. Пока оба файла включены в компиляцию, а пространство имен второго типа используется, доступно, тогда ваш класс будет доступен.

Пример:

Class1.cs

namespace Project1 { 
 class Class1 { ... }
}

Class2.cs

namespace Project1 {
  class Class2 {
    private Class1 m_field1;
    ..
  }
}

Ответ 4

Также не забывайте, что частичные классы С# имеют некоторую функциональность, которую вы могли бы получить с помощью операторов #include.

Частичные классы позволяют разбить определение класса на несколько файлов.

Ответ 6

Немного неясно, что вы имеете в виду. Но вы думаете о:

using MyNamespace;

Ответ 8

Это не совсем так, как директива С#include, но С# using statement - это то, что вы после:

using Assembly.Name;

Он работает на уровне пространства имен, а не на уровне файла. Итак, если class.cs включает открытый класс с именем SomeClass в пространстве имен Application.Core, это будет выглядеть так:

using Application.Core;

Обычно это размещается в верхней части файла, в котором вы работаете, и позволял этому классу использовать SomeClass как объект (вместе со всеми другими общедоступными классами в пространстве имен Application.Core).

Конечно, если все классы находятся в одном и том же пространстве имен (например, Application.Core), нет оснований вообще использовать инструкцию using. Классы в пределах одного пространства имен могут разрешать друг друга без каких-либо деклараций.

Ответ 9

Вам нужно будет поместить содержимое class.cs в пространство имен. А затем поставьте оператор using в верхней части файла, который должен увидеть class.cs.

class.cs
namespace Class {
//class.cs stuff
}

Затем выполните следующие действия в файле, который нуждается в классе.

  using Class;

Ответ 10

пример с использованием 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");
}