.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 संस्करण की तुलना में बहुत बेहतर है।
यदि किसी के पास कोई सुझाव है कि संकलन-समय सुरक्षा के लिए इस कोड को कैसे बेहतर बनाया जाए, तो कृपया टिप्पणी करें!