У меня есть функция:
public long GiveMeTwoTimesTwo()
{
return 2 * 2;
}
Эта функция отстой. Что если я хочу 3 * 3?
public long GiveMeThreeTimesThree()
{
return 3 * 3;
}
Слишком много печатать. Я ленивый!
public long SquareOf(int n)
{
return n * n;
}
Моя SquareOf
функция не имеет значения, что такое n
. Он будет работать правильно для любого переданного n
. Он не знает точно, что такое число n
, но он знает , что n
является целым числом. Вы не можете передать "Haha not an integer"
в SquareOf
.
Вот еще одна функция:
public void DoSomethingRad()
{
int x = 4;
long y = SquareOf(x);
Console.WriteLine(y);
}
Вопреки своему названию, DoSomethingRad фактически ничего не делает, рад. Тем не менее, он пишет SquareOf (4), который равен 16. Можем ли мы изменить его на менее скучный?
public void DoSomethingRad(int numberToSquare)
{
long y = SquareOf(numberToSquare);
Console.WriteLine(y);
}
DoSomethingRad
явно все еще довольно неудачно. Но, по крайней мере, теперь мы можем передать число в квадрат, чтобы оно не записывало 16 каждый раз. (Он напишет 1, или 4, или 9, или 16, или ... zzzz все еще скучно).
Было бы хорошо, если бы был способ изменить то, что происходит с переданным числом. Может быть, мы не хотим ставить его в квадрат; может быть, мы хотим его кубировать или вычесть из 69 (число, выбранное случайным образом из моей головы).
При дальнейшем осмотре кажется, что единственная часть SquareOf
, о которой DoSomethingRad
заботится, - это то, что мы можем дать ей целое число (numberToSquare
) и что она дает нам long
(потому что мы ставим его возвращаемое значение в y
и y
равно long
).
public long CubeOf(int n)
{
return n * n * n;
}
public void DoSomethingLeet(int numberToSquare)
{
long y = CubeOf(numberToSquare);
Console.WriteLine(y);
}
Посмотрите, насколько DoSomethingLeet
похож на DoSomethingRad
? Если бы только был способ передать поведение (DoX()
) вместо просто data (int n
) ...
Так что теперь, если мы хотим написать квадрат числа, мы можем DoSomethingRad
, а если мы хотим написать куб числа, мы можем DoSomethingLeet
. Итак, если мы хотим написать число, вычтенное из 69, нужно ли нам делать другой метод, DoSomethingCool
? Нет, потому что это чертовски много печатает (и что еще более важно, это мешает нам изменять интересное поведение, изменяя только один аспект нашей программы).
Итак, мы приходим к:
public long Radlicious(int doSomethingToMe, Func<int, long> doSomething)
{
long y = doSomething(doSomethingToMe);
Console.WriteLine(y);
}
Мы можем вызвать этот метод, написав это:
Radlicious(77, SquareOf);
Func<int, long>
- особый вид делегата. Он хранит поведение, которое принимает целые числа и выплевывает long
с. Мы не уверены, что метод, на который он указывает, будет делать с любым заданным нами целым числом; все, что мы знаем, это то, что, что бы ни случилось, мы вернем long
.
Нам не нужно задавать какие-либо параметры для SquareOf
, потому что Func<int, long>
описывает поведение , а не данные. Вызов Radlicious(77, SquareOf)
просто дает Radlicious общее поведение SquareOf
(«Я беру число и возвращаю его квадрат»), а не то, что SquareOf
сделает с любым конкретным целым числом.
Теперь, если вы поняли, о чем я говорю, значит, вы уже превзошли меня, потому что я сам этого не понимаю.
* КОНЕЦ ОТВЕТА, НАЧИНАЮТ СТРАНУЮ ИДИОЦИЮ *
Я имею в виду, кажется, что int
s может восприниматься как просто очень скучное поведение:
static int Nine()
{
return 9;
}
Тем не менее, грань между тем, что представляет собой данные, и поведением, кажется, размыта, а то, что обычно воспринимается как данные, является просто скучным поведением.
Конечно, можно представить супер «интересное» поведение, которое принимает все виды абстрактных параметров, но требует, чтобы тонна информации могла его вызвать. Что если нам потребуется предоставить исходный код, который он скомпилирует и запустит для нас?
Что ж, тогда наша абстракция, кажется, вернула нас обратно на круги своя. У нас такое абстрактное поведение, что для определения того, что он собирается делать, требуется весь исходный код нашей программы. Это полностью неопределенное поведение: функция может делать что угодно , но для определения того, что она делает, ей нужно предоставить everything . С другой стороны, полностью определенное поведение, такое как Nine()
, не нуждается в дополнительной информации, но не может ничего сделать, кроме возврата 9
.
И что? Я не знаю.