응용 프로그램을 설계 할 때 Func <> 및 Action <>을 어떻게 사용합니까?
내가 Func을 <>과 액션 <>에 대해 찾을 수있는 모든 예제는 간단한 당신이 볼 경우 아래와 같이 방법 들이 기술적으로 작업하지만 난 그들이 이전에 해결 또는 수 수없는 문제를 해결 예에서 사용 된보고 싶다 더 복잡한 방식으로 만 해결되어야합니다. 즉, 작동 방식을 알고 있으며 간결하고 강력 하다는 것을 알 수 있습니다 . 따라서 어떤 종류의 문제를 해결하고 어떻게 사용할 수 있는지 에 대해 더 큰 의미 로 이해하고 싶습니다 . 응용 프로그램 디자인.
실제 문제를 해결하기 위해 Func <> 및 Action <>을 어떤 방법 (패턴)으로 사용합니까?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestFunc8282
{
class Program
{
static void Main(string[] args)
{
//func with delegate
Func<string, string> convert = delegate(string s)
{
return s.ToUpper();
};
//func with lambda
Func<string, string> convert2 = s => s.Substring(3, 10);
//action
Action<int,string> recordIt = (i,title) =>
{
Console.WriteLine("--- {0}:",title);
Console.WriteLine("Adding five to {0}:", i);
Console.WriteLine(i + 5);
};
Console.WriteLine(convert("This is the first test."));
Console.WriteLine(convert2("This is the second test."));
recordIt(5, "First one");
recordIt(3, "Second one");
Console.ReadLine();
}
}
}
또한 switch 문을 리팩토링하는 데 유용합니다.
다음 (단순하지만) 예제를 사용하십시오.
public void Move(int distance, Direction direction)
{
switch (direction)
{
case Direction.Up :
Position.Y += distance;
break;
case Direction.Down:
Position.Y -= distance;
break;
case Direction.Left:
Position.X -= distance;
break;
case Direction.Right:
Position.X += distance;
break;
}
}
Action 대리자를 사용하여 다음과 같이 리팩터링 할 수 있습니다.
static Something()
{
_directionMap = new Dictionary<Direction, Action<Position, int>>
{
{ Direction.Up, (position, distance) => position.Y += distance },
{ Direction.Down, (position, distance) => position.Y -= distance },
{ Direction.Left, (position, distance) => position.X -= distance },
{ Direction.Right, (position, distance) => position.X += distance },
};
}
public void Move(int distance, Direction direction)
{
_directionMap[direction](this.Position, distance);
}
linq 사용.
List<int> list = { 1, 2, 3, 4 };
var even = list.Where(i => i % 2);
의 매개 변수 Where
는 Func<int, bool>
.
Lambda 식은 C #에서 제가 가장 좋아하는 부분 중 하나입니다. :)
나는 항상 Action
및 Func
델리게이트를 사용합니다 . 일반적으로 공간을 절약하기 위해 람다 구문으로 선언하고 주로 큰 메서드의 크기를 줄이는 데 사용합니다. 방법을 검토 할 때 비슷한 코드 세그먼트가 눈에 띄는 경우가 있습니다. 이 경우 유사한 코드 세그먼트를 Action
또는 로 래핑합니다 Func
. 델리게이트를 사용하면 중복 코드가 줄어들고 코드 세그먼트에 멋진 서명이 제공되며 필요한 경우 메서드로 쉽게 승격 될 수 있습니다.
저는 델파이 코드를 작성했고 함수 내에서 함수를 선언 할 수있었습니다. Action과 Func는 C #에서 저에게 동일한 동작을 수행합니다.
다음은 대리자를 사용하여 컨트롤 위치를 변경하는 샘플입니다.
private void Form1_Load(object sender, EventArgs e)
{
//adjust control positions without delegate
int left = 24;
label1.Left = left;
left += label1.Width + 24;
button1.Left = left;
left += button1.Width + 24;
checkBox1.Left = left;
left += checkBox1.Width + 24;
//adjust control positions with delegate. better
left = 24;
Action<Control> moveLeft = c =>
{
c.Left = left;
left += c.Width + 24;
};
moveLeft(label1);
moveLeft(button1);
moveLeft(checkBox1);
}
내가 사용하는 한 가지는 동일한 입력이 주어지면 변경되지 않는 값 비싼 메서드 호출을 캐싱하는 것입니다.
public static Func<TArgument, TResult> Memoize<TArgument, TResult>(this Func<TArgument, TResult> f)
{
Dictionary<TArgument, TResult> values;
var methodDictionaries = new Dictionary<string, Dictionary<TArgument, TResult>>();
var name = f.Method.Name;
if (!methodDictionaries.TryGetValue(name, out values))
{
values = new Dictionary<TArgument, TResult>();
methodDictionaries.Add(name, values);
}
return a =>
{
TResult value;
if (!values.TryGetValue(a, out value))
{
value = f(a);
values.Add(a, value);
}
return value;
};
}
기본 재귀 피보나치 예제 :
class Foo
{
public Func<int,int> Fibonacci = (n) =>
{
return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
};
public Foo()
{
Fibonacci = Fibonacci.Memoize();
for (int i=0; i<50; i++)
Console.WriteLine(Fibonacci(i));
}
}
Dunno 같은 질문에 두 번 대답하거나 대답하지 않는 것이 나쁜 형식이라면 일반적으로 이러한 유형의 더 나은 사용에 대한 아이디어를 얻으려면 Jeremy Miller의 함수형 프로그래밍에 대한 MSDN 기사를 읽는 것이 좋습니다.
Action을 사용하여 트랜잭션에서 실행중인 데이터베이스 작업을 멋지게 캡슐화합니다.
public class InTran
{
protected virtual string ConnString
{
get { return ConfigurationManager.AppSettings["YourDBConnString"]; }
}
public void Exec(Action<DBTransaction> a)
{
using (var dbTran = new DBTransaction(ConnString))
{
try
{
a(dbTran);
dbTran.Commit();
}
catch
{
dbTran.Rollback();
throw;
}
}
}
}
이제 트랜잭션에서 실행하려면 간단히
new InTran().Exec(tran => ...some SQL operation...);
InTran 클래스는 공통 라이브러리에 상주하여 중복을 줄이고 향후 기능 조정을위한 단일 위치를 제공합니다.
By keeping them generic and supporting multiple arguments, it allows us to avoid having to create strong typed delegates or redundant delegates that do the same thing.
Actually, i found this at stackoverflow (at least - the idea):
public static T Get<T>
(string cacheKey, HttpContextBase context, Func<T> getItemCallback)
where T : class
{
T item = Get<T>(cacheKey, context);
if (item == null) {
item = getItemCallback();
context.Cache.Insert(cacheKey, item);
}
return item;
}
I have a separate form that accepts a generic Func or an Action in the constructor as well as some text. It executes the Func/Action on a separate thread while displaying some text in the form and showing an animation.
It's in my personal Util library, and I use it whenever I want to do a medium length operation and block the UI in a non-intrusive way.
I considered putting a progress bar on the form as well, so that it could perform longer running operations but I haven't really needed it to yet.
'developer tip' 카테고리의 다른 글
매개 변수를 사용하거나 사용하지 않고 사용할 수있는 Python 데코레이터를 만드는 방법은 무엇입니까? (0) | 2020.11.05 |
---|---|
WSDL이 웹 서비스의 SOAP 버전 (1.1 또는 1.2)을 나타낼 수 있습니까? (0) | 2020.11.05 |
날짜에 대한 PDO :: PARAM? (0) | 2020.11.05 |
두 개의 CPU가있는 VirtualBox로 Vagrant에서 VM을 어떻게 만들 수 있습니까? (0) | 2020.11.05 |
Google 애드워즈 전환 onclick을 추적하는 방법은 무엇입니까? (0) | 2020.11.04 |