Может ли С# определять макросы, как это делается на языке программирования C, с инструкциями перед процессором? Я хотел бы упростить регулярное типирование некоторых повторяющихся утверждений, таких как:
Console.WriteLine("foo");
Может ли С# определять макросы, как это делается на языке программирования C, с инструкциями перед процессором? Я хотел бы упростить регулярное типирование некоторых повторяющихся утверждений, таких как:
Console.WriteLine("foo");
Нет, С# не поддерживает макросы препроцессора, такие как C. Visual Studio, с другой стороны, имеет фрагменты. Фрагменты Visual Studio - это функция IDE и расширены в редакторе, а не заменены в коде при компиляции препроцессором.
Вы можете использовать препроцессор C (например, mcpp) и установить его в файл .csproj. Затем вы выполняете "build action" в исходном файле из "Скомпилировать в Preprocess" или как вы его называете. Просто добавьте BeforBuild в свой .csproj следующим образом:
<Target Name="BeforeBuild" Inputs="@(Preprocess)" Outputs="@(Preprocess->'%(Filename)_P.cs')">
<Exec Command="..\Bin\cpp.exe @(Preprocess) -P -o %(RelativeDir)%(Filename)_P.cs" />
<CreateItem Include="@(Preprocess->'%(RelativeDir)%(Filename)_P.cs')">
<Output TaskParameter="Include" ItemName="Compile" />
</CreateItem>
Возможно, вам придется вручную скомпилировать Compile to Preprocess по крайней мере в одном файле (в текстовом редакторе) - тогда опция "Preprocess" должна быть доступна для выбора в Visual Studio.
Я знаю, что макросы сильно злоупотребляют и злоупотребляют, но удаление их полностью одинаково плохо, если не хуже. Классическим примером использования макросов будет NotifyPropertyChanged. Каждый программист, которому пришлось переписать этот код вручную тысячи раз, знает, насколько он болезнен без макросов.
Я использую это, чтобы избежать Console.WriteLine(...)
:
public static void Cout(this string str, params object[] args) {
Console.WriteLine(str, args);
}
а затем вы можете использовать следующее:
"line 1".Cout();
"This {0} is an {1}".Cout("sentence", "example");
это кратким и любезным напуганным.
Пока вы не можете писать макросы, когда дело доходит до упрощения таких вещей, как ваш пример, С# 6.0 теперь предлагает статические приложения. Здесь пример Мартина Перника дал его среднюю статью:
using static System.Console; // Note the static keyword
namespace CoolCSharp6Features
{
public class Program
{
public static int Main(string[] args)
{
WriteLine("Hellow World without Console class name prefix!");
return 0;
}
}
}
Прямой эквивалент макросов C-стиля в С#, но inline
d статические методы - с или без #if
/#elseif
/#else
прагмы - это самое близкое, которое вы можете получить:
/// <summary>
/// Prints a message when in debug mode
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Log(object message) {
#if DEBUG
Console.WriteLine(message);
#endif
}
/// <summary>
/// Prints a formatted message when in debug mode
/// </summary>
/// <param name="format">A composite format string</param>
/// <param name="args">An array of objects to write using format</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Log(string format, params object[] args) {
#if DEBUG
Console.WriteLine(format, args);
#endif
}
/// <summary>
/// Computes the square of a number
/// </summary>
/// <param name="x">The value</param>
/// <returns>x * x</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Square(double x) {
return x * x;
}
/// <summary>
/// Wipes a region of memory
/// </summary>
/// <param name="buffer">The buffer</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void ClearBuffer(ref byte[] buffer) {
ClearBuffer(ref buffer, 0, buffer.Length);
}
/// <summary>
/// Wipes a region of memory
/// </summary>
/// <param name="buffer">The buffer</param>
/// <param name="offset">Start index</param>
/// <param name="length">Number of bytes to clear</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void ClearBuffer(ref byte[] buffer, int offset, int length) {
fixed(byte* ptrBuffer = &buffer[offset]) {
for(int i = 0; i < length; ++i) {
*(ptrBuffer + i) = 0;
}
}
}
Это отлично работает как макрос, но имеет небольшой недостаток: методы, помеченные как inline
d, будут скопированы в часть отражения вашей сборки, как и любой другой "нормальный" метод.
К счастью, у С# нет препроцессора в стиле C/С++ - поддерживаются только условная компиляция и прагмы (и, возможно, что-то еще, что я не могу вспомнить). К сожалению, у С# нет возможностей метапрограммирования (это может в какой-то мере иметь отношение к вашему вопросу).
Поверните макрос C в статический метод С# в классе.
Я бы предложил вам написать расширение, что-то вроде ниже.
public static class WriteToConsoleExtension
{
// Extension to all types
public static void WriteToConsole(this object instance,
string format,
params object[] data)
{
Console.WriteLine(format, data);
}
}
class Program
{
static void Main(string[] args)
{
Program p = new Program();
// Usage of extension
p.WriteToConsole("Test {0}, {1}", DateTime.Now, 1);
}
}
Надеюсь, что это поможет (и не слишком поздно:))
Поскольку С# 7.0 поддерживает using static
директив и локальных функций, для большинства случаев вам не нужны макросы препроцессора.