สำหรับ. NET 2.0 นี่เป็นโค้ดที่ดีที่ฉันเขียนซึ่งทำในสิ่งที่คุณต้องการอย่างแน่นอนและใช้ได้กับคุณสมบัติใด ๆ ในControl
:
private delegate void SetControlPropertyThreadSafeDelegate(
Control control,
string propertyName,
object propertyValue);
public static void SetControlPropertyThreadSafe(
Control control,
string propertyName,
object propertyValue)
{
if (control.InvokeRequired)
{
control.Invoke(new SetControlPropertyThreadSafeDelegate
(SetControlPropertyThreadSafe),
new object[] { control, propertyName, propertyValue });
}
else
{
control.GetType().InvokeMember(
propertyName,
BindingFlags.SetProperty,
null,
control,
new object[] { propertyValue });
}
}
เรียกว่าเป็นแบบนี้:
// thread-safe equivalent of
// myLabel.Text = status;
SetControlPropertyThreadSafe(myLabel, "Text", status);
หากคุณใช้. NET 3.0 ขึ้นไปคุณสามารถเขียนวิธีการด้านบนเป็นวิธีการขยายของControl
คลาสซึ่งจะทำให้การโทรไปที่:
myLabel.SetPropertyThreadSafe("Text", status);
อัพเดท 05/10/2010:
สำหรับ. NET 3.0 คุณควรใช้รหัสนี้:
private delegate void SetPropertyThreadSafeDelegate<TResult>(
Control @this,
Expression<Func<TResult>> property,
TResult value);
public static void SetPropertyThreadSafe<TResult>(
this Control @this,
Expression<Func<TResult>> property,
TResult value)
{
var propertyInfo = (property.Body as MemberExpression).Member
as PropertyInfo;
if (propertyInfo == null ||
!@this.GetType().IsSubclassOf(propertyInfo.ReflectedType) ||
@this.GetType().GetProperty(
propertyInfo.Name,
propertyInfo.PropertyType) == null)
{
throw new ArgumentException("The lambda expression 'property' must reference a valid property on this Control.");
}
if (@this.InvokeRequired)
{
@this.Invoke(new SetPropertyThreadSafeDelegate<TResult>
(SetPropertyThreadSafe),
new object[] { @this, property, value });
}
else
{
@this.GetType().InvokeMember(
propertyInfo.Name,
BindingFlags.SetProperty,
null,
@this,
new object[] { value });
}
}
ซึ่งใช้ LINQ และแลมบ์ดานิพจน์เพื่อให้ได้ไวยากรณ์ที่สะอาดขึ้นง่ายขึ้นและปลอดภัยยิ่งขึ้น:
myLabel.SetPropertyThreadSafe(() => myLabel.Text, status); // status has to be a string or this will fail to compile
ไม่เพียง แต่ชื่อคุณสมบัติจะถูกตรวจสอบ ณ เวลาที่คอมไพล์ แต่ชนิดของคุณสมบัติก็เช่นกันดังนั้นจึงเป็นไปไม่ได้ (เช่น) กำหนดค่าสตริงให้กับคุณสมบัติบูลีนและทำให้เกิดข้อยกเว้นรันไทม์
น่าเสียดายที่สิ่งนี้ไม่ได้ขัดขวางไม่ให้ใครทำสิ่งที่โง่เขลาเช่นการส่งผ่านControl
ทรัพย์สินและคุณค่าของผู้อื่นดังนั้นสิ่งต่อไปนี้จะรวบรวมอย่างมีความสุข:
myLabel.SetPropertyThreadSafe(() => aForm.ShowIcon, false);
ดังนั้นฉันจึงเพิ่มการตรวจสอบรันไทม์เพื่อให้แน่ใจว่าคุณสมบัติที่ผ่านเข้ามาไม่ได้เป็นของControl
วิธีการที่เรียกใช้ ไม่สมบูรณ์ แต่ยังดีกว่ารุ่น. NET 2.0 มาก
หากใครมีข้อเสนอแนะเพิ่มเติมเกี่ยวกับวิธีการปรับปรุงรหัสนี้เพื่อความปลอดภัยเวลารวบรวมโปรดแสดงความคิดเห็น!