나는 C # 대리자를 개념적으로 이해한다고 생각하지만, 그들이 유용한 실제 사례를 찾는 데 어려움을 겪고 있습니다. 실제 응용 프로그램에서 C # 대리자가 사용 된 방식과 문제를 해결할 수있는 문제에 대해 자세히 설명 할 수 있습니까?
나는 C # 대리자를 개념적으로 이해한다고 생각하지만, 그들이 유용한 실제 사례를 찾는 데 어려움을 겪고 있습니다. 실제 응용 프로그램에서 C # 대리자가 사용 된 방식과 문제를 해결할 수있는 문제에 대해 자세히 설명 할 수 있습니까?
답변:
GUI 코드는 델리게이트를 사용하여 버튼 클릭, 창 이동과 같은 이벤트를 처리합니다. 델리게이트를 사용하면 이벤트가 발생할 때마다 호출되는 함수를 가질 수 있습니다. 예를 들어 인터페이스의 "저장"버튼에 데이터를 저장하는 기능을 연결하는 것이 있습니다. 버튼을 클릭하면 데이터를 저장하는 기능을 실행하도록 설정됩니다. 전체 프로그램이 사용자가 무언가를 할 때까지 기다릴 수 있고 GUI가 무엇을 먼저 할 것인지 알 수 없기 때문에 GUI 프로그래밍에 유용합니다. 델리게이트를 사용하면 사용자가 원하는 방식으로 작업을 수행 할 수있는 방식으로 프로그램의 기능을 UI에 연결할 수 있습니다.
관찰자 패턴을 사용하는 거의 모든 것이 대의원을 구현할 것입니다.
설명을 읽으면 사용할 시나리오를 상상할 수 있습니다. GUI 이벤트 처리가 일반적인 예입니다.
Fortran 및 C와 같은 비 OOP 언어의 "오래된 날"에는 서브 루틴이 함수에 대한 포인터 인 인수를 수신하도록하는 것이 매우 유용했습니다. 예를 qsort
들어이 기능은 사용자 제공 비교 기능과 함께 작동합니다. 일반적인 미분 방정식을 풀거나 함수를 최적화하기위한 수많은 서브 루틴이 있으며, 모두 함수 포인터를 인수로 사용합니다.
윈도우 시스템에서 모든 종류의 콜백은 동일한 패턴을 따릅니다.
Lisp에는 초기에도 "기능적 논증"또는 FUNARG라는 것이 있었는데, 이는 기능 일뿐 아니라 외부 세계의 일부를 기억하고 상호 작용할 수있는 스토리지 컨텍스트도 포함했습니다.
함수의 주소를 전달할 때 함수의 메소드 인 객체의 주소도 전달해야한다는 점을 제외하고는 OOP 언어에서도 이와 같은 요구가 존재합니다. 그것은 당신이 통과해야 할 두 가지입니다. 따라서 델리게이트는 바로 그 것이며 오래된 패턴을 계속 사용할 수 있습니다.
다음은 DRY 원칙을 따르는 간단한 코드를 만들 때 델리게이트가 얼마나 유용한 지 보여주는 간단한 예입니다. 또한 코드를 필요한 곳에 매우 가깝게 유지할 수 있습니다.
Action<Button, Action<Button>> prepareButton =
(btn, nxt) => {
btn.Height = 32;
btn.Width= 64;
nxt(btn);
};
prepareButton(myBtn1, btn => btn.Text = "A");
prepareButton(myBtn2, btn => btn.Text = "B");
prepareButton(myBtn3, btn => btn.Text = "C");
다음은 대의원이 제공하는 이점의 실제 예입니다.
protected override void PageInitialize()
{
const string selectCodeFormat = "javascript:selectCode('{0}', '{1}');";
const string onClick = "return toggleElement(this);";
Func<HtmlGenericControl> getElement = null;
Action<HtmlGenericControl> setElement = null, addChild = null;
HtmlGenericControl level1Element = null, level2Element = null, level3Element = null, level4Element = null;
string className = null, code = null, description = null;
using (var records = Core.Database.ExecuteRecords("code.SocCodeTree"))
{
while (records.Read())
{
code = records.GetString("Code");
description = records.GetString("Description");
if (records.GetString("Level4") != "")
{
className = "Level4";
setElement = e => level4Element = e;
getElement = () => level4Element;
addChild = e => level3Element.Controls.Add(e);
}
else if (records.GetString("Level3") != "")
{
className = "Level3";
setElement = e => level3Element = e;
getElement = () => level3Element;
addChild = e => level2Element.Controls.Add(e);
}
else if (records.GetString("Level2") != "")
{
className = "Level2";
setElement = e => level2Element = e;
getElement = () => level2Element;
addChild = e => level1Element.Controls.Add(e);
}
else
{
className = "Level1";
setElement = e => level1Element = e;
getElement = () => level1Element;
addChild = e => Root.Controls.Add(e);
}
var child = new HtmlGenericControl("li");
child.Attributes["class"] = className;
var span = new HtmlGenericControl("span") {
InnerText = code + " - " + description + " - "
};
span.Attributes["onclick"] = onClick;
child.Controls.Add(span);
var a = new HtmlAnchor() {
InnerText = "Select",
HRef = string.Format(selectCodeFormat, code, description)
};
child.Controls.Add(a);
setElement(new HtmlGenericControl("ul"));
child.Controls.Add(getElement());
addChild(child);
}
}
}