มันคืออะไรFunc<>
และใช้ทำอะไร?
If you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
มันคืออะไรFunc<>
และใช้ทำอะไร?
If you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
คำตอบ:
Func<T>
T
เป็นชนิดที่ผู้ร่วมประชุมที่กำหนดไว้ล่วงหน้าสำหรับวิธีการที่จะส่งกลับค่าของชนิดบาง
กล่าวอีกนัยหนึ่งคุณสามารถใช้ประเภทนี้เพื่ออ้างอิงวิธีการที่ส่งคืนค่าบางส่วนของT
. เช่น
public static string GetMessage() { return "Hello world"; }
อาจมีการอ้างอิงเช่นนี้
Func<string> f = GetMessage;
Func<T>
คือdelegate TResult Func<out TResult>()
. ไม่มีข้อโต้แย้ง Func<T1, T2>
จะเป็นฟังก์ชันที่ใช้อาร์กิวเมนต์เดียว
static int OneArgFunc(this string i) { return 42; }
Func<int> f = "foo".OneArgFunc;
. =)
Extension
แอตทริบิวต์ซึ่งอ่านโดยคอมไพเลอร์ C # / VB.Net เท่านั้นไม่ใช่ CLR โดยทั่วไปวิธีการของอินสแตนซ์ (ซึ่งแตกต่างจากฟังก์ชันคงที่) จะมีพารามิเตอร์ 0th "this" ซ่อนอยู่ ดังนั้นวิธีการอินสแตนซ์ 1 อาร์กิวเมนต์จึงคล้ายกับฟังก์ชันคงที่ 2 อาร์กิวเมนต์ จากนั้นเราจะมีผู้เข้าร่วมประชุมซึ่งจัดเก็บเป้าหมายวัตถุและฟังก์ชั่นตัวชี้ ผู้รับมอบสิทธิ์สามารถจัดเก็บอาร์กิวเมนต์แรกในเป้าหมายหรือไม่ทำเช่นนั้น
คิดว่าเป็นตัวยึด จะมีประโยชน์มากเมื่อคุณมีโค้ดที่เป็นไปตามรูปแบบที่กำหนด แต่ไม่จำเป็นต้องเชื่อมโยงกับฟังก์ชันเฉพาะใด ๆ
ตัวอย่างเช่นพิจารณาEnumerable.Select
วิธีการขยาย
วิธีนี้ใช้Func<T, TResult>
แทนฟังก์ชันคอนกรีตใด ๆ สิ่งนี้ช่วยให้สามารถใช้ในบริบทใด ๆที่ใช้รูปแบบข้างต้น
ตัวอย่างเช่นสมมติว่าฉันมีList<Person>
และฉันต้องการเพียงแค่ชื่อของทุกคนในรายการ ฉันสามารถทำได้:
var names = people.Select(p => p.Name);
หรือบอกว่าฉันต้องการอายุของทุกคน:
var ages = people.Select(p => p.Age);
ทันทีคุณจะเห็นว่าฉันสามารถใช้ประโยชน์จากรหัสเดียวกันที่แสดงรูปแบบ (ด้วยSelect
) ด้วยฟังก์ชันที่แตกต่างกันสองฟังก์ชัน ( p => p.Name
และp => p.Age
) ได้อย่างไร
อีกทางเลือกหนึ่งคือเขียนเวอร์ชันอื่นSelect
ทุกครั้งที่คุณต้องการสแกนลำดับเพื่อหาค่าประเภทอื่น ดังนั้นเพื่อให้ได้ผลเช่นเดียวกับข้างต้นฉันจะต้อง:
// Presumably, the code inside these two methods would look almost identical;
// the only difference would be the part that actually selects a value
// based on a Person.
var names = GetPersonNames(people);
var ages = GetPersonAges(people);
ด้วยตัวแทนที่ทำหน้าที่เป็นตัวยึดตำแหน่งฉันจึงปลดปล่อยตัวเองจากการเขียนรูปแบบเดิมซ้ำแล้วซ้ำเล่าในกรณีเช่นนี้
Func<T1, T2, ..., Tn, Tr>
แสดงถึงฟังก์ชันที่ใช้อาร์กิวเมนต์ (T1, T2, ... , Tn) และส่งกลับ Tr
ตัวอย่างเช่นหากคุณมีฟังก์ชัน:
double sqr(double x) { return x * x; }
คุณสามารถบันทึกเป็นตัวแปรฟังก์ชัน:
Func<double, double> f1 = sqr;
Func<double, double> f2 = x => x * x;
จากนั้นใช้เหมือนกับที่คุณใช้ sqr:
f1(2);
Console.WriteLine(f2(f1(4)));
เป็นต้น
โปรดจำไว้ว่าเป็นผู้รับมอบสิทธิ์สำหรับข้อมูลขั้นสูงเพิ่มเติมโปรดดูเอกสารประกอบ
ฉันพบว่าFunc<T>
มีประโยชน์มากเมื่อฉันสร้างส่วนประกอบที่จำเป็นต้องปรับให้เหมาะกับแต่ละบุคคล "ทันที"
ยกตัวอย่างง่ายๆนี้: PrintListToConsole<T>
ส่วนประกอบ
อ็อบเจ็กต์ง่ายๆที่พิมพ์รายการอ็อบเจ็กต์นี้ไปยังคอนโซล คุณต้องการให้นักพัฒนาที่ใช้มันปรับแต่งผลลัพธ์
ตัวอย่างเช่นคุณต้องการให้เขากำหนดรูปแบบตัวเลขประเภทใดประเภทหนึ่งเป็นต้น
ไม่มี Func
ขั้นแรกคุณต้องสร้างอินเทอร์เฟซสำหรับคลาสที่รับอินพุตและสร้างสตริงเพื่อพิมพ์ไปยังคอนโซล
interface PrintListConsoleRender<T> {
String Render(T input);
}
จากนั้นคุณต้องสร้างคลาสPrintListToConsole<T>
ที่ใช้อินเทอร์เฟซที่สร้างไว้ก่อนหน้านี้และใช้กับแต่ละองค์ประกอบของรายการ
class PrintListToConsole<T> {
private PrintListConsoleRender<T> _renderer;
public void SetRenderer(PrintListConsoleRender<T> r) {
// this is the point where I can personalize the render mechanism
_renderer = r;
}
public void PrintToConsole(List<T> list) {
foreach (var item in list) {
Console.Write(_renderer.Render(item));
}
}
}
นักพัฒนาที่จำเป็นต้องใช้ส่วนประกอบของคุณจะต้อง:
ใช้อินเทอร์เฟซ
ผ่านชั้นเรียนจริงไปยัง PrintListToConsole
class MyRenderer : PrintListConsoleRender<int> {
public String Render(int input) {
return "Number: " + input;
}
}
class Program {
static void Main(string[] args) {
var list = new List<int> { 1, 2, 3 };
var printer = new PrintListToConsole<int>();
printer.SetRenderer(new MyRenderer());
printer.PrintToConsole(list);
string result = Console.ReadLine();
}
}
การใช้ Func นั้นง่ายกว่ามาก
ภายในคอมโพเนนต์คุณกำหนดพารามิเตอร์ประเภทFunc<T,String>
ที่แสดงถึงอินเทอร์เฟซของฟังก์ชันที่รับพารามิเตอร์อินพุตประเภท T และส่งคืนสตริง (เอาต์พุตสำหรับคอนโซล)
class PrintListToConsole<T> {
private Func<T, String> _renderFunc;
public void SetRenderFunc(Func<T, String> r) {
// this is the point where I can set the render mechanism
_renderFunc = r;
}
public void Print(List<T> list) {
foreach (var item in list) {
Console.Write(_renderFunc(item));
}
}
}
เมื่อนักพัฒนาใช้คอมโพเนนต์ของคุณเขาก็ส่งผ่านไปยังคอมโพเนนต์การใช้งานFunc<T, String>
ประเภทนั่นคือฟังก์ชันที่สร้างเอาต์พุตสำหรับคอนโซล
class Program {
static void Main(string[] args) {
var list = new List<int> { 1, 2, 3 }; // should be a list as the method signature expects
var printer = new PrintListToConsole<int>();
printer.SetRenderFunc((o) => "Number:" + o);
printer.Print(list);
string result = Console.ReadLine();
}
}
Func<T>
ช่วยให้คุณกำหนดอินเทอร์เฟซวิธีการทั่วไปได้ทันที
คุณกำหนดประเภทของอินพุตและประเภทของเอาต์พุต เรียบง่ายและกระชับ
Func<T1,R>
และอื่น ๆ ที่กำหนดไว้ล่วงหน้าทั่วไปFunc
ที่ได้รับมอบหมาย ( Func<T1,T2,R>
, Func<T1,T2,T3,R>
และอื่น ๆ ) เป็นผู้ได้รับมอบหมายทั่วไปที่ส่งกลับชนิดของพารามิเตอร์ทั่วไปที่ผ่านมา
หากคุณมีฟังก์ชันที่ต้องการส่งคืนประเภทต่างๆขึ้นอยู่กับพารามิเตอร์คุณสามารถใช้Func
ผู้รับมอบสิทธิ์โดยระบุประเภทการส่งคืน
เป็นเพียงผู้รับมอบสิทธิ์ทั่วไปที่กำหนดไว้ล่วงหน้า การใช้งานคุณไม่จำเป็นต้องประกาศผู้รับมอบสิทธิ์ทุกคน มีผู้รับมอบสิทธิ์ที่กำหนดไว้ล่วงหน้าอีกรายหนึ่งAction<T, T2...>
ซึ่งเหมือนกัน แต่กลับเป็นโมฆะ
อาจจะยังไม่สายเกินไปที่จะเพิ่มข้อมูลบางอย่าง
ผลรวม:
Func คือผู้รับมอบสิทธิ์แบบกำหนดเองที่กำหนดไว้ในเนมสเปซของระบบที่อนุญาตให้คุณชี้ไปที่วิธีการที่มีลายเซ็นเดียวกัน (ตามที่ผู้รับมอบสิทธิ์ทำ) โดยใช้พารามิเตอร์อินพุต 0 ถึง 16 และต้องส่งคืนบางสิ่ง
ศัพท์เฉพาะและ how2use:
Func<input_1, input_2, ..., input1_6, output> funcDelegate = someMethod;
ความหมาย:
public delegate TResult Func<in T, out TResult>(T arg);
ที่ใช้:
ใช้ในนิพจน์แลมบ์ดาและวิธีการที่ไม่ระบุตัวตน