Перейти к содержимому

Как вызвать функцию в си шарп

  • автор:

Как вызвать данную функцию?

введите сюда описание изображения

Посоветую пойти через другой путь. Перепишем метод (параметр с типом EventArgs , а не PaintEventArgs при клике на кнопку):

private void button3_Click(object sender, EventArgs e) < textBox2.Text = cez(textBox2.Text); // Заставить форму перерисовываться вместе с изображением (вызовется метод OnPaint) this.Invalidate(); >

По-хорошему, нужно хранить признак типа Boolean в приватных филдах формы, чтобы пониамть, что Вы вызвали рисование при нажатии на кнопку. Далее перегрузим метод рисования:

protected override void OnPaint(PaintEventArgs e) < // Не забываем вызвать базовый метод, чтобы перерисовалась форма base.OnPaint(e); // Вызываем ваш самописный метод и передаем в него PaintEventArgs pictureBox1.Image = picture(e); >

Метод немного упростится (убираем object sender ):

public Image picture(PaintEventArgs e) < string str = textBox2.Text; foreach (char c in str) < switch (c) < case '1': white(e); break; case '0': black(e); break; >> return Image; > 

Ну и из двух дпугих методов убираем ненужный параметр:

public void white(PaintEventArgs e) < Random random = new Random(); int x = random.Next(0, 100); int y = random.Next(0, 100); e.Graphics.FillRectangle(Brushes.White, x, y, 1, 1); >public void black(PaintEventArgs e)

Получить из EventArgs тип PaintEventArgs не получится, зато можно инициировать отправку сообщения рисования элементу управления. Почитать про инересный метод можно тут: Control.Invalidate

Методы (Руководство по программированию на C#)

Метод — это блок кода, содержащий ряд инструкций. Программа инициирует выполнение инструкций, вызывая метод и указывая все аргументы, необходимые для этого метода. В C# все инструкции выполняются в контексте метода.

Метод Main является точкой входа для каждого приложения C# и вызывается общеязыковой средой выполнения (CLR) при запуске программы. В приложении, использующем инструкции верхнего уровня, метод Main создается компилятором и содержит все инструкции верхнего уровня.

В этой статье рассматриваются названные методы. Дополнительные сведения об анонимных функциях см. в статье Лямбда-выражения.

Сигнатуры методов

Методы объявляются в классе, структуре или интерфейсе путем указания уровня доступа, такого как public или private , необязательных модификаторов, таких как abstract или sealed , возвращаемого значения, имени метода и всех параметров этого метода. Все эти части вместе представляют собой сигнатуру метода.

Тип возврата метода не является частью сигнатуры метода в целях перегрузки метода. Однако он является частью сигнатуры метода при определении совместимости между делегатом и методом, который он указывает.

Параметры метода заключаются в скобки и разделяются запятыми. Пустые скобки указывают, что параметры методу не требуются. Этот класс содержит четыре метода:

abstract class Motorcycle < // Anyone can call this. public void StartEngine() // Only derived classes can call this. protected void AddGas(int gallons) < /* Method statements here */ >// Derived classes can override the base class implementation. public virtual int Drive(int miles, int speed) < /* Method statements here */ return 1; >// Derived classes must implement this. public abstract double GetTopSpeed(); > 

Доступ к методу

Вызов метода в объекте аналогичен доступу к полю. После имени объекта добавьте точку, имя метода и круглые скобки. Аргументы перечисляются в этих скобках и разделяются запятыми. Таким образом, методы класса Motorcycle могут вызываться, как показано в следующем примере:

class TestMotorcycle : Motorcycle < public override double GetTopSpeed() < return 108.4; >static void Main() < TestMotorcycle moto = new TestMotorcycle(); moto.StartEngine(); moto.AddGas(15); moto.Drive(5, 20); double speed = moto.GetTopSpeed(); Console.WriteLine("My top speed is ", speed); > > 

Параметры и аргументы метода

Определение метода задает имена и типы всех необходимых параметров. Когда вызывающий код вызывает метод, он предоставляет конкретные значения, называемые аргументами, для каждого параметра. Аргументы должны быть совместимы с типом параметра, но имя аргумента (если есть), используемое в вызывающем коде, не обязательно должно совпадать с именем параметра, указанным в методе. Например:

public void Caller() < int numA = 4; // Call with an int variable. int productA = Square(numA); int numB = 32; // Call with another int variable. int productB = Square(numB); // Call with an integer literal. int productC = Square(12); // Call with an expression that evaluates to int. productC = Square(productA * 3); >int Square(int i) < // Store input argument in a local variable. int input = i; return input * input; >

Передача по ссылке и передача по значению

По умолчанию при передаче в метод экземпляра типа значения вместо самого этого экземпляра передается его копия. Поэтому изменения в аргументе не оказывают влияния на исходный экземпляр в вызывающем методе. Чтобы передать экземпляр типа значения по ссылке, используйте ключевое слово ref . Дополнительные сведения см. в разделе Передача параметров типа значения.

При передаче в метод объекта ссылочного типа передается ссылка на этот объект. То есть метод получает не сам объект, а аргумент, который указывает расположение объекта. При изменении члена объекта с помощью этой ссылки это изменение отражается в аргументе в вызывающем методе, даже если объект передается по значению.

Ссылочный тип создается с помощью ключевого слова class , как показано в следующем примере.

public class SampleRefType

Теперь, если передать объект, основанный на этом типе, в метод, то будет передана ссылка на объект. В следующем примере объект типа SampleRefType передается в метод ModifyObject :

public static void TestRefType() < SampleRefType rt = new SampleRefType(); rt.value = 44; ModifyObject(rt); Console.WriteLine(rt.value); >static void ModifyObject(SampleRefType obj)

В этом примере, в сущности, делается то же, что и в предыдущем примере, — аргумент по значению передается в метод. Но поскольку здесь используется ссылочный тип, результат будет другим. В данном случае в методе ModifyObject изменено поле value параметра obj , а также изменено поле value аргумента, rt в методе TestRefType . В качестве выходных данных метод TestRefType отображает 33.

Дополнительные сведения о передаче ссылочных типов по ссылке и по значению см. в разделах Передача параметров ссылочного типа и Ссылочные типы.

Возвращаемые значения

Методы могут возвращать значение вызывающему объекту. Если тип возврата, указываемый перед именем метода, не void , этот метод может возвращать значение с помощью оператора return . Инструкция с ключевым словом return , за которым следует значение, соответствующее типу возврата, будет возвращать это значение объекту, вызвавшему метод.

Значение можно вернуть вызывающему объекту по значению или по ссылке. Значения возвращаются вызывающему объекту по ссылке, если ключевое слово ref используется в сигнатуре метода и указывается после каждого ключевого слова return . Например, следующая сигнатура метода и оператор return указывают, что метод возвращает переменную с именем estDistance вызывающему объекту по ссылке.

public ref double GetEstimatedDistance()

Ключевое слове return также останавливает выполнение метода. Если тип возврата — void , инструкцию return без значения по-прежнему можно использовать для завершения выполнения метода. Без ключевого слова return этот метод будет останавливать выполнение при достижении конца блока кода. Методы с типом возврата, отличным от void, должны использовать ключевое слово return для возврата значения. Например, в следующих двух методах ключевое слово return используется для возврата целочисленных значений.

class SimpleMath < public int AddTwoNumbers(int number1, int number2) < return number1 + number2; >public int SquareANumber(int number) < return number * number; >> 

Чтобы использовать значение, возвращаемое из метода, вызывающий метод может применять сам вызов метода везде, где будет достаточно значения того же типа. Можно также назначить возвращаемое значение переменной. Например, следующие два примера кода достигают одной и той же цели.

int result = obj.AddTwoNumbers(1, 2); result = obj.SquareANumber(result); // The result is 9. Console.WriteLine(result); 
result = obj.SquareANumber(obj.AddTwoNumbers(1, 2)); // The result is 9. Console.WriteLine(result); 

Использование локальной переменной, в данном случае result , для сохранения значения является необязательным. Это может улучшить читаемость кода или может оказаться необходимым, если нужно сохранить исходное значение аргумента для всей области метода.

Чтобы использовать значение, возвращаемое по ссылке из метода, необходимо объявить локальную ссылочную переменную, если планируется изменение значения. Например, если метод Planet.GetEstimatedDistance возвращает значение Double по ссылке, можно определить его как локальную ссылочную переменную с использованием кода следующего вида:

ref double distance = ref Planet.GetEstimatedDistance(); 

Возвращать многомерный массив из метода M , который изменяет содержимое массива, необязательно, если вызывающая функция передает массив в M . В целях оптимизации можно возвращать полученный массив из M или функциональный поток значений, однако это необязательно. Это связано с тем, что C# передает все ссылочные типы по значению, а значение ссылки на массив представляет собой указатель на массив. В методе M любые изменения содержимого массива отслеживаются любым кодом, имеющим ссылку на массив, как показано в приведенном ниже примере:

static void Main(string[] args) < int[,] matrix = new int[2, 2]; FillMatrix(matrix); // matrix is now full of -1 >public static void FillMatrix(int[,] matrix) < for (int i = 0; i < matrix.GetLength(0); i++) < for (int j = 0; j < matrix.GetLength(1); j++) < matrix[i, j] = -1; >> > 

Асинхронные методы

С помощью функции async можно вызывать асинхронные методы, не прибегая к использованию явных обратных вызовов или ручному разделению кода между несколькими методами или лямбда-выражениями.

Если пометить метод с помощью модификатора async, можно использовать в этом методе инструкцию await. Когда управление достигает выражения await в асинхронном методе, управление возвращается вызывающему объекту и выполнение метода приостанавливается до завершения выполнения ожидающей задачи. После завершения задачи выполнение в методе может быть возобновлено.

Асинхронный метод возвращается в вызывающий объект, когда он встречает первый ожидаемый объект, выполнение которого еще не завершено, или когда выполнение асинхронного метода доходит до конца — в зависимости от того, что происходит раньше.

В следующем примере метод Main служит примером асинхронного метода с типом возврата Task. Он переходит к методу DoSomethingAsync и, поскольку он выражается в одной строке, он может опустить ключевые слова async и await . Поскольку DoSomethingAsync является асинхронным методом, задача для вызова DoSomethingAsync должна быть ожидаемой, как показывает следующая инструкция: await DoSomethingAsync(); .

class Program < static Task Main() =>DoSomethingAsync(); static async Task DoSomethingAsync() < TaskdelayTask = DelayAsync(); int result = await delayTask; // The previous two statements may be combined into // the following statement. //int result = await DelayAsync(); Console.WriteLine($"Result: "); > static async Task DelayAsync() < await Task.Delay(100); return 5; >> // Example output: // Result: 5 

Асинхронный метод не может объявить все параметры ref или out , но может вызывать методы, которые имеют такие параметры.

Определения текста выражений

Часто используются определения методов, которые просто немедленно возвращаются с результатом выражения или которые имеют единственную инструкцию в тексте метода. Для определения таких методов существует сокращенный синтаксис с использованием => :

public Point Move(int dx, int dy) => new Point(x + dx, y + dy); public void Print() => Console.WriteLine(First + " " + Last); // Works with operators, properties, and indexers too. public static Complex operator +(Complex a, Complex b) => a.Add(b); public string Name => First + " " + Last; public Customer this[long id] => store.LookupCustomer(id); 

Если метод возвращает void или является асинхронным методом, то текст метода должен быть выражением инструкции (так же, как при использовании лямбда-выражений). Свойства и индексаторы должны быть только для чтения, и вы не должны использовать ключевое слово get метода доступа.

Итераторы

Итератор выполняет настраиваемую итерацию по коллекции, например по списку или массиву. Итератор использует инструкцию yield return для возврата всех элементов по одному. При достижении инструкции yield return текущее расположение в коде запоминается. При следующем вызове итератора выполнение возобновляется с этого места.

Итератор вызывается из клиентского кода с помощью инструкции foreach .

Дополнительные сведения см. в разделе Итераторы.

Спецификация языка C#

Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

См. также

  • Руководство по программированию на C#
  • Система типов C#
  • Модификаторы доступа
  • Статические классы и члены статических классов
  • Наследование
  • Абстрактные и запечатанные классы и члены классов
  • params
  • out
  • ref;
  • Параметры методов

Совместная работа с нами на GitHub

Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.

Локальные функции (руководство по программированию на C#)

Локальные функции — это методы типа, вложенного в другой член. Они могут вызываться только из того элемента, в который вложены. Ниже перечислены элементы, в которых можно объявлять и из которых можно вызывать локальные функции:

  • Методы, в частности методы итератора и асинхронные методы
  • Конструкторы
  • Методы доступа к свойствам
  • Методы доступа событий
  • Анонимные методы
  • Лямбда-выражения
  • Методы завершения
  • Другие локальные функции

Тем не менее локальные функции нельзя объявлять внутри элемента, воплощающего выражение.

В некоторых случаях для реализации возможностей, поддерживаемых локальными функциями, также можно использовать лямбда-выражения. Дополнительные сведения см. в разделе Локальные функции или лямбда-выражения.

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

Синтаксис локальной функции

Локальная функция определяется как вложенный метод внутри содержащего ее элемента. Ниже приведен синтаксис определения локальной функции:

Не должен содержать параметры, именованные с контекстными ключевое слово value . Компилятор создает временную переменную «value», которая содержит ссылки на внешние переменные, которые позже вызывают неоднозначность, а также может привести к неожиданному поведению.

С локальной функцией можно использовать следующие модификаторы:

  • async
  • unsafe
  • static Статическую локальную функцию нельзя записывать локальные переменные или состояние экземпляра.
  • extern Должна быть static внешняя локальная функция.

Все локальные переменные, определенные в содержащем функцию элементе (включая параметры метода), доступны в нестатической локальной функции.

В отличие от определения метода, определение локальной функции не может содержать модификатор доступа к элементу. Поскольку все локальные функции являются частными, при использовании модификатора доступа (например, ключевого слова private ) возникает ошибка компилятора CS0106, «Модификатор «private» недопустим для этого элемента».

В следующем примере определяется локальная функция AppendPathSeparator , которая является частной для метода GetText :

private static string GetText(string path, string filename) < var reader = File.OpenText($""); var text = reader.ReadToEnd(); return text; string AppendPathSeparator(string filepath) < return filepath.EndsWith(@"\") ? filepath : filepath + @"\"; >> 

Атрибуты можно применить к локальной функции, его параметрам и параметрам типа, как показано в следующем примере:

#nullable enable private static void Process(string?[] lines, string mark) < foreach (var line in lines) < if (IsValid(line)) < // Processing logic. >> bool IsValid([NotNullWhen(true)] string? line) < return !string.IsNullOrEmpty(line) && line.Length >= mark.Length; > > 

В предыдущем примере используется специальный атрибут для помощи компилятору в статическом анализе в контексте, допускающем значение NULL.

Локальные функции и исключения

Полезной особенностью локальных функций является то, что они допускают немедленную обработку исключений. Для методов итератора исключения отображаются только при перечислении возвращаемой последовательности, а не при извлечении итератора. В случае с асинхронными методами любые исключения, возникшие в таком методе, наблюдаются в тот момент, когда возвращаемая задача находится в состоянии ожидания.

В следующем примере определяется метод OddSequence , который перечисляет нечетные числа в заданном диапазоне. Поскольку он передает в метод перечислителя OddSequence число больше 100, этот метод вызывает исключение ArgumentOutOfRangeException. Как видно из выходных данных этого примера, исключение обрабатывается только в момент перебора чисел, а не при извлечении перечислителя.

public class IteratorWithoutLocalExample < public static void Main() < IEnumerablexs = OddSequence(50, 110); Console.WriteLine("Retrieved enumerator. "); foreach (var x in xs) // line 11 < Console.Write($""); > > public static IEnumerable OddSequence(int start, int end) < if (start < 0 || start >99) throw new ArgumentOutOfRangeException(nameof(start), "start must be between 0 and 99."); if (end > 100) throw new ArgumentOutOfRangeException(nameof(end), "end must be less than or equal to 100."); if (start >= end) throw new ArgumentException("start must be less than end."); for (int i = start; i > > // The example displays the output like this: // // Retrieved enumerator. // Unhandled exception. System.ArgumentOutOfRangeException: end must be less than or equal to 100. (Parameter 'end') // at IteratorWithoutLocalExample.OddSequence(Int32 start, Int32 end)+MoveNext() in IteratorWithoutLocal.cs:line 22 // at IteratorWithoutLocalExample.Main() in IteratorWithoutLocal.cs:line 11 

Если поместить логику итератора в локальную функцию, при получении перечислителя вызываются исключения проверки аргументов, как показано в следующем примере:

public class IteratorWithLocalExample < public static void Main() < IEnumerablexs = OddSequence(50, 110); // line 8 Console.WriteLine("Retrieved enumerator. "); foreach (var x in xs) < Console.Write($""); > > public static IEnumerable OddSequence(int start, int end) < if (start < 0 || start >99) throw new ArgumentOutOfRangeException(nameof(start), "start must be between 0 and 99."); if (end > 100) throw new ArgumentOutOfRangeException(nameof(end), "end must be less than or equal to 100."); if (start >= end) throw new ArgumentException("start must be less than end."); return GetOddSequenceEnumerator(); IEnumerable GetOddSequenceEnumerator() < for (int i = start; i > > > // The example displays the output like this: // // Unhandled exception. System.ArgumentOutOfRangeException: end must be less than or equal to 100. (Parameter 'end') // at IteratorWithLocalExample.OddSequence(Int32 start, Int32 end) in IteratorWithLocal.cs:line 22 // at IteratorWithLocalExample.Main() in IteratorWithLocal.cs:line 8 

Локальные функции или лямбда-выражения

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

Рассмотрим различия в реализации алгоритма вычисления факториала с использованием локальной функции и лямбда-выражения. В этой версии используется локальная функция:

public static int LocalFunctionFactorial(int n) < return nthFactorial(n); int nthFactorial(int number) =>number

В этой версии используются лямбда-выражения:

public static int LambdaFactorial(int n) < FuncnthFactorial = default(Func); nthFactorial = number => number

Именование

Локальные функции явно именуются как методы. Лямбда-выражения представляют собой анонимные методы и должны назначаться переменным типа delegate , как правило, типа Action или Func . Процесс объявления локальной функции аналогичен написанию обычного метода: вы объявляете тип возвращаемого значения и сигнатуру функции.

Сигнатуры функций и типы лямбда-выражений

Лямбда-выражения используют тип переменной Action / Func , которой они назначаются, для определения типов аргументов и возвращаемых значений. Поскольку синтаксис локальных функций во многом аналогичен обычному методу, типы аргументов и возвращаемых значений уже входят в объявление функции.

Начиная с C# 10, некоторые лямбда-выражения имеют естественный тип, который позволяет компилятору определить тип возвращаемого значения и типы параметров лямбда-выражения.

Определенное назначение

Лямбда-выражения — это объекты, которые объявляются и назначаются во время выполнения. Чтобы использовать лямбда-выражение, его необходимо определенно назначить: для этого необходимо объявить переменную Action / Func , которой оно будет назначено, и назначить ей лямбда-выражение. Обратите внимание на то, что LambdaFactorial должно объявить и инициализировать лямбда-выражение nthFactorial , прежде чем его определить. В противном случае возникает ошибка компилятора, связанная со ссылкой на объект nthFactorial , который еще не был назначен.

Локальные функции определяются во время компиляции. Они не назначаются переменным, в связи с чем на них можно ссылаться из любого расположения кода, в области действия которого они находятся. В первом примере LocalFunctionFactorial мы можем объявить локальную функцию выше или ниже инструкции return , и это не приведет к ошибкам компилятора.

Эти различия означают, что рекурсивные алгоритмы легче создавать, используя локальные функции. Можно объявить и определить локальную функцию, которая вызывает саму себя. Необходимо объявить лямбда-выражения и назначить им значение по умолчанию, прежде чем их можно будет переназначить телу, которое ссылается на то же лямбда-выражение.

Реализация в виде делегата

Лямбда-выражения преобразуются в делегаты при объявлении. Локальные функции являются более гибкими и могут определяться в виде традиционного метода или делегата. Локальные функции преобразуются в делегаты только при использовании в качестве делегата.

Если объявить локальную функцию и сослаться на нее только путем вызова этой функции в качестве метода, она не будет преобразована в делегат.

Захват переменной

Правила определенного назначения также влияют на любые переменные, захватываемые локальной функцией или лямбда-выражением. Компилятор может выполнять статический анализ, что позволяет локальным функциям определенно назначать захватываемые переменные во включающей области. Рассмотрим следующий пример:

int M() < int y; LocalFunction(); return y; void LocalFunction() =>y = 0; > 

Компилятор может определить, что LocalFunction определенно назначает y при вызове. Поскольку LocalFunction вызывается перед оператором return , y определенно назначается в операторе return .

Обратите внимание, что когда локальная функция захватывает переменные во включающей области, эта функция реализуется как тип делегата.

Распределение куч

В зависимости от использования при работе с локальными функциями можно избежать распределения куч, которое всегда необходимо выполнять при работе с лямбда-выражениями. Если локальная функция никогда не преобразуется в делегат и ни одна из переменных, захваченных локальной функцией, не захвачена другими лямбда-выражениями или локальными функциями, которые преобразуются в делегаты, компилятор может избежать распределения куч.

Рассмотрим следующий асинхронный пример:

public async Task PerformLongRunningWorkLambda(string address, int index, string name) < if (string.IsNullOrWhiteSpace(address)) throw new ArgumentException(message: "An address is required", paramName: nameof(address)); if (index < 0) throw new ArgumentOutOfRangeException(paramName: nameof(index), message: "The index must be non-negative"); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException(message: "You must supply a name", paramName: nameof(name)); Func longRunningWorkImplementation = async () => < var interimResult = await FirstWork(address); var secondResult = await SecondStep(index, name); return $"The results are and . Enjoy."; >; return await longRunningWorkImplementation(); > 

Замыкание для этого лямбда-выражения содержит переменные address , index и name . При использовании локальных функций объект, который реализует замыкание, может иметь тип struct . Этот тип структуры будет передан в локальную функцию посредством ссылки. Эта разница в реализации позволяет избежать распределения.

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

Если известно, что локальная функция не будет преобразована в делегат и ни одна из захватываемых ею переменных не захватывается другими лямбда-выражениями или локальными функциями, которые преобразуются в делегаты, то можно гарантировать, что локальная функция не будет распределяться в куче за счет объявления в качестве локальной функции static .

Включите правило стиля кода .NET IDE0062 , чтобы гарантировать, что локальные функции всегда помечены static .

В эквивалентном этому методе на основе локальной функции также используется класс для замыкания. Реализация замыкания для локальной функции в формате class или struct зависит от особенностей реализации. Локальная функция может использовать struct , тогда как в лямбда-выражениях всегда используется class .

public async Task PerformLongRunningWork(string address, int index, string name) < if (string.IsNullOrWhiteSpace(address)) throw new ArgumentException(message: "An address is required", paramName: nameof(address)); if (index < 0) throw new ArgumentOutOfRangeException(paramName: nameof(index), message: "The index must be non-negative"); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException(message: "You must supply a name", paramName: nameof(name)); return await longRunningWorkImplementation(); async TasklongRunningWorkImplementation() < var interimResult = await FirstWork(address); var secondResult = await SecondStep(index, name); return $"The results are and . Enjoy."; > > 

Использование ключевого слова yield

Еще одно преимущество локальных функций, которое не показано в этом примере, заключается в том, что они могут быть реализованы в качестве итераторов с использованием синтаксиса yield return для создания последовательности значений.

public IEnumerable SequenceToLowercase(IEnumerable input) < if (!input.Any()) < throw new ArgumentException("There are no items to convert to lowercase."); >return LowercaseIterator(); IEnumerable LowercaseIterator() < foreach (var output in input.Select(item =>item.ToLower())) < yield return output; >> > 

В лямбда-выражениях не допускается использование оператора yield return . Дополнительные сведения см. в разделе об ошибке компилятора CS1621.

Локальные функции могут показаться избыточными для лямбда-выражений, поскольку обычно применяются иначе и в других целях. Локальные функции более эффективны в случаях, когда вам нужно написать функцию, которая будет вызываться только из контекста другого метода.

Спецификация языка C#

См. также

  • Используйте локальную функцию вместо лямбда-правила (правило стиля IDE0039)
  • Методы

Совместная работа с нами на GitHub

Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.

Как вызвать функцию в си шарп

Всем здрасте .
Я так и не смог придумать адекватный текст заголовка, так как мой вопрос не вмещается в 3-5 слов.
Суть такова:
У меня есть семь функций, и массив bool[], содержащий семь значений, которые определяют, стоит ли вызывать каждую из семи функций.
Вопрос: можно ли это сделать циклически ?
Абстрактно:

for (byte i=0;i<7;i++) if (arr[i]) Вызвать функцию, к которой привязан этот элемент массива

Я знаю только один способ вызвать функцию - напрямую, по её имени. Но, к моему сожалению этот способ не позволяет мне вызывать так несколько функций так, как бы мне этого хотелось.
Можно ли так сделать, и если да - то как ?
Понятно, что эти семь функций надо где то сохранить, но я даже не знаю, как написать запрос в гугле.
На запрос "c# ссылка на функцию" я нашёл, что это из области неуправляемого кода, и не кошерно мешать управляемый и неуправляемый код.

Подпись ? Не, не слышал .
Последний раз редактировалось OmegaBerkut; 19.11.2016 в 23:30 .

OmegaBerkut
Посмотреть профиль
Найти ещё сообщения от OmegaBerkut

Регистрация: 12.01.2011
Сообщений: 19,500
delegate, Action, Func, .
Участник клуба
Регистрация: 21.10.2015
Сообщений: 1,361
зачем отвязывать функцию от массива? лист> или еще чего подходящегоcome-on, я не понял вашего вопроса .
Как мне посоветовал Alex11223 - я создал массив, и обращаюсь к нему:

Func[] functions=new Func[7]; functions[0]=new Func(MyFunc1); // и так далее по аналогии // . output=functions[i].Invoke(input); // в цикле

При этом, в моём случае все мои функции выполняют изменение input таким образом, что на каждой итерации цикла в output сохраняется изменённая строка input. Но это уже другая история.

Сейчас у меня появился ещё один вопрос, по теме ссылок, только теперь не на функции, а на значения .
В моём классе есть несколько значений. У каждого значения есть компонент интерфейса, отвечающий за содержимое отдельно взятого значения.
Дабы не городить 16 обработчиков событий на каждый компонент (ровно столько у меня компонентов, и их значений в классе) - я хочу организовать редактирование значения, которое я предварительно сохраняю в свойство Tag каждого компонента (при его создании). Вопрос такой: как в Tag сохранять ссылку на значение класса, для дальнейшего редактирования значения через эту ссылку ?
Абстрактно:

textBox1.Tag=example.assigntext; // это должно быть сохранение ссылки на значение // . textBox1.Tag="Hello, world !"; // при этом example.assigntext должно измениться

На C++ так будет работать, если при записи значения перед example.assigntext поставить амперсанд (&) . Так как это не передача параметра в функцию - ref не прокатит. Как это дело организовать на C# ?

Подпись ? Не, не слышал .

OmegaBerkut
Посмотреть профиль
Найти ещё сообщения от OmegaBerkut

Участник клуба
Регистрация: 21.10.2015
Сообщений: 1,361
example.assigntext = "Hello, world !";
Спокойный псих
Участник клуба
Регистрация: 19.03.2013
Сообщений: 1,538

come-on
У меня таких assigntext'ов 16 штук, ровно столько же и компонентов интерфейса для их редактирования. Так конечно сделать можно, но будет некрасиво - 16 обработчиков событий.

Подпись ? Не, не слышал .

OmegaBerkut
Посмотреть профиль
Найти ещё сообщения от OmegaBerkut

Регистрация: 28.01.2009
Сообщений: 20,999
sender это тот на ком вызвано событие

Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.

Пепел Феникса
Посмотреть профиль
Найти ещё сообщения от Пепел Феникса

Спокойный псих
Участник клуба
Регистрация: 19.03.2013
Сообщений: 1,538

Пепел Феникса
Та же яичница, только в профиль: 16 кейсов. UPD: поправочка - для самих сендеров кейс неприменим. Так что - (sender as TextBox).Name.
Хотелось бы, что бы интерфейсная реализация содержала один обработчик события для редактирования одного типа данных. При этом - код обработчика может содержать всего одну строку. Я знаю, что такое можно сделать на С++, спрашиваю про аналог на C#.
Для примера - код обработчика события интерфейсной реализации:

((sender as CheckBox).Tag as Control).Enabled=(sender as CheckBox).Checked;

Таким образом у каждого CheckBox на форме существует свой контрол, который нужно включать/выключать.
Но это экземпляры классов - с ними, в данном случае, проще.
Как быть с переменными ?

Подпись ? Не, не слышал .
Последний раз редактировалось OmegaBerkut; 20.11.2016 в 21:10 .

OmegaBerkut
Посмотреть профиль
Найти ещё сообщения от OmegaBerkut

Регистрация: 28.01.2009
Сообщений: 20,999

у вас есть лямбды, у вас есть делегаты, вы можете создавать структуры/классы.
полет фантазии неограничен.

Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.

Пепел Феникса
Посмотреть профиль
Найти ещё сообщения от Пепел Феникса

Спокойный псих
Участник клуба
Регистрация: 19.03.2013
Сообщений: 1,538
Сообщение от Пепел Феникса

у вас есть лямбды, у вас есть делегаты, вы можете создавать структуры/классы.
полет фантазии неограничен.

Я много чего не знаю . По C#, ровно как и по С++. И, есть те вещи, которые я знаю, как делаются в C++, но не знаю, как делаются в C#; ровно как и наоборот.
Так вот .
Что такое лямбды - я не знаю (не приходилось ещё сталкиваться) .
Что такое делегаты - я имею представление . Если говорить аналогиями - это зародыши генериков. Но опять же - сталкиваться непосредственно с делегатами приходилось только при обращении к компоненту из потока.
К чему я веду всю эту ересь .
Я задал вполне корректный и конкретный вопрос - как сделать это, привёл аналогию из родственного языка, написал псевдо-код того, что я хочу получить.
А в ответе получаю словосочетания без инструкций к их применению. Ну, или то, что другие люди называют "философией программирования" - в моём маленьком круге студентов-программистов под этим выражением подразумевается несуразная ересь. Или необоснованные, ни с чем не связанные данные.
Как вы лично, Пепел Феникса, предлагаете мне на такое реагировать ?

Говоря проще - внятного ответа на свой (второй) вопрос я так и не получил.
P. S. Я понимаю, что мне тут никто ничего не должен; но - если отвечаете, то отвечайте, пожалуйста, по существу.

Подпись ? Не, не слышал .
Последний раз редактировалось OmegaBerkut; 21.11.2016 в 00:40 .

OmegaBerkut
Посмотреть профиль
Найти ещё сообщения от OmegaBerkut

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *