|
If you need any additional information, then Luc Pattyn's post below is a good read. When you aren't accessing any Controls, it's very similar to normal, single-threaded programming. The only exception is synchronisation - if you're modifying a variable in multiple Threads, then make sure it's synchronised otherwise you might end up with a race condition
|
|
|
|
|
Hi,
you get one of my standard replies:
Controls are not thread-safe, hence they should be touched (that is: their methods or properties called) only by the thread that created them, which normally is the main thread (aka GUI thread). Creating some controls on a different thread is unlikely to be successful, since all Controls get linked somehow: they reside on Forms, Forms are related to each other (by Parent, by Z-Order, etc), so normally all are created on a single thread.
If you violate the “don’t touch Controls from another thread” rule and are running .NET version 2.0 or above you will get an InvalidOperationException (“Cross-thread operation not valid”), which should be remedied by changing the code.
Do not set Control.CheckForIllegalCrossThreadCalls false, since that does hide the exception but does not cure the fundamental flaw in your code, so it just postpones the moment of failure, which typically will show as a non-responsive and possibly badly painted GUI.
Here are some ways to get another thread:
- explicitly launching a Thread instance
- exclicitly delegating some work to a ThreadPool thread
- using a BackgroundWorker; a BGW is a separate thread with the advantage that two of its events (ProgressChanged and RunWorkerCompleted) execute on the GUI thread; however the bulk of the work normally is handled in the DoWork handler which runs on a distinct thread.
- using timers other than System.Windows.Forms.Timer; the Forms timer ticks on the GUI thread, all other use different threads to handle the periodic event;
- using asynchronous input/output, such as the DataReceived event of the SerialPort class
Any of these touching a single method or property of a Control is sufficient to create havoc; there are 5 exceptions:
- the InvokeRequired property
- the Invoke, BeginInvoke, EndInvoke and CreateGraphics methods (the latter only if the handle for the control has already been created).
If there is a need to touch the Control from another thread, one must use an Invoke pattern, which in C# basically looks like this (VB.NET would be very similar):
public void SetText(string text) {
if (myControl.InvokeRequired) {
myControl.Invoke(new Action< string >(SetText),
new object[] {text});
} else {
myControl.Text=text;
}
}
|
|
|
|
|
I have seen you post this 'standard reply' atleast 4 times a week.
|
|
|
|
|
That doesn't make it any less useful. I've got it bookmarked, and it answers common questions well
|
|
|
|
|
There are people who read (almost) everything on one or several forums, and it is to warn them for a repeat answer that I start with a sentence about "standard reply".
And there are people who don't read anything at all, all they do is post a question when they have one; for the most "popular" problems, I have standard replies and I just copy/paste them from my repository to the message editor window, that is more efficient that retyping similar answers all the time.
BTW: the standard replies evolve over time; when they are incorrect, incomplete, or misunderstood, I tend to improve them. And no, they don't come with a version number. yet.
|
|
|
|
|
lol... the 'standard reply' is a good one... and like you said not every1 reads them. You should plan on versioning your 'standard replys'. It will help the few people who actually read it.
|
|
|
|
|
Hello,
I'm trying to access an element from the following function, can you help me ?
I've tried a lot of constructions without success.
Edit:
I`m using VS2008\.NET 3.5
The function below should access the "i" value for single types and arrays at the same time, for single types it`s ok, but for arrays I don`t know how to access array elements. I can check i.GetType().IsArray, but don`t know how to access particular elements.
static void function<t>(ref T i)
{
string s;
if ( !i.GetType().IsArray )
s = i.ToString(); // ok
else
// next line doesn't compile: Cannot apply indexing with [] to an expression of type 'T'
int a = i[0];
}
Caller code example:
int a = 5;
function(ref a);
int[] arri = { 3, 5, 7 };
function(ref arri);
Thanks for any help.
|
|
|
|
|
static void function(ref T[] i)
Your code declares i as a T. In order to access it as an array, you need to specify it as one (unless you like pointer arithmetic and a whole world of pain). But your function code is concerning. The idea of generics is to make something type-safe. What happens if T is a String? A nasty error. Incidentally, you should have gotten another error at the invocation point (something like "Cannot implicitly convert between int[] and int")
|
|
|
|
|
You have to declare the argument as an array if it is one. Like so:
static void function(ref T[] i)
But your next line:
int a = i[0];
won't compile anyway, since the compiler cannot garantuee that T is of a type that is convertible to an int .
Use something like this instead:
static void function(ref T[] i) where T : struct
{
try
{
int a = Convert.ToInt(i[0]);
}
catch((FormatException)
{
}
...
Regards
Thomas
www.thomas-weller.de
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. Programmer - an organism that turns coffee into software.
|
|
|
|
|
Thanks Thomas, I edit the question and explained it better. My problem is basically to access the "i" value when the function receive single types and arrays too, my problem is to get the value of each element when the type is an array (which I can check using i.GetType().IsArray).
Thanks anyway.
|
|
|
|
|
Then there's a small problem with my code. Try this:
public static IEnumerable<t> GetIEnumerable<t>(T input)
{
if(input is IEnumerable<t>)
{
foreach(T element in (input as IEnumerable<t>))
yield return element;
}
else
yield return input;
}</t></t></t></t>
As a bonus, this also deals with all IEnumerables (ArrayLists, List<t>s, etc), not just arrays. You could replace IEnumerable<t> with T[] and get your original query.
|
|
|
|
|
It doesn't work: Unable to cast object of type 'System.Int32' to type 'System.Int32[]'.
|
|
|
|
|
In this case you can simply declare two overloads, one for normal elements and one for arrays:
static void function(ref T i)
{
DoSomething(i);
}
static void function(ref T[] i)
{
foreach(T element in i)
{
DoSomething(element);
}
}
static void DoSomething(ref T i)
{
...
}
Regards
Thomas
www.thomas-weller.de
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. Programmer - an organism that turns coffee into software.
|
|
|
|
|
Thomas Weller wrote:
catch(FormatException)
FTFY (extra bracket)
|
|
|
|
|
I was wondering if somehow it is possible to make objects readonly if referenced by another assembly but writeable when accessed internally?
For example I have a scenario where I need to pass objects to UI. UI must not be allowed to temper with the object in any form or fashion but the business layer should have full access to the object as we need to do some computation after the object is inialized by the DAL.
I was just wondering if there is a preferred way of dealing with situations like these that I am not aware of?
Would appreciate the help ...
Thanks in advance.
|
|
|
|
|
Like so?
private int p;
public int Property
{
internal set { p = value; }
get { return p; }
}
warning: untested
|
|
|
|
|
student_rhr wrote: I was just wondering if there is a preferred way of dealing with situations like these
There are three ways (that I know of... ):
1.
Create an interface that only declares the elements (e.g. property getters) that the UI should see. 'Implement' it on the class of interest (actually you only have to declare it). Then pass this interface around instead of the 'real' object.
2.
Implement the Data Transfer Object design pattern to handle the situation. It is described here^. In
short, this method declares a struct or immutable class with all the data of interest, and if you have to pass around
these data you create such an object (with a copy of the relevant data) for this purpose.
3.
Declare the objects property setters and methods (if they are able to change the objects state) as internal, everything else as public. 'Internal' means exactly that: Public for everything inside the same assembly, invisible for everything outside.
What best suits your needs depends on your overall architecture and the situation...
Hope this helps.
Regards
Thomas
www.thomas-weller.de
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. Programmer - an organism that turns coffee into software.
|
|
|
|
|
Something like automatic properties? (Not available in .Net framework versions below 3.0)
public MyType Property { get; internal set; }
|
|
|
|
|
I have a class that is serializable (using the SerializableAttribute). I have also implemented the ISerializable to that class. I am able to serialize/deserialize the object by doing the following:
string xml = string.Empty;
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
StringWriter sw = new StringWriter();
settings.OmitXmlDeclaration = true;
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(sw, settings))
{
XmlSerializer ser = new XmlSerializer(typeof(Content));
ser.Serialize(writer, this, ns);
return sw.ToString();
}
My problem is when I try to bind the object to a ViewState, I get the following error:
Type 'System.Xml.XmlNode' in Assembly 'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable
Below are my classes (shortened). Any help is appreciated. Thanks in advance.
Content Class:
[Serializable]
[DataObject(true)]
public class Content : ISerializable
{
public Content() { }
public Content(SerializationInfo info, StreamingContext context)
{
this.contentCollection = (List<Content> )info.GetValue("ContentCollection", typeof(List<Content> ));
this.ContentId = info.GetInt64("ContentId");
this.Name = info.GetString("Name");
this.Owner = (Owner)info.GetValue("Owner", typeof(Owner));
}
private List<Content> contentCollection;
[XmlArray("ContentCollection")]
public List<content> ContentCollection
{
get
{
if (contentCollection == null) contentCollection = new List<content>();
return this.contentCollection;
}
}
private System.Int64 contentIdField;
[XmlAttribute("ContentId")]
public System.Int64 ContentId
{
get { return this.contentIdField; }
set { this.contentIdField = value; }
}
private System.String nameField;
[XmlElement("Name")]
public System.String Name
{
get { return this.nameField; }
set { this.nameField = value; }
}
private Owner owner;
[XmlElement("Owner")]
public Owner Owner
{
get { return this.owner; }
set { this.owner = value; }
}
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("ContentCollection", this.ContentCollection);
info.AddValue("ContentId", this.ContentId);
info.AddValue("Name", this.Name);
info.AddValue("Owner", this.Owner);
}
#endregion</content></content>
Owner Class:
[Serializable]
[DataObject(true)]
public class Owner : ISerializable
{
public Owner() { }
public Owner(SerializationInfo info, StreamingContext context)
{
this.OwnerId = info.GetInt64("OwnerId");
}
private long ownerId;
[Browsable(false)]
[XmlAttribute("OwnerId")]
public long OwnerId
{
get { return ownerId; }
set { ownerId = value; }
}
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("OwnerId", this.ownerId);
}
#endregion
}
|
|
|
|
|
Turns out ViewStates does not support Xml Objec serialization. Instead it uses the LosFormatter so BinaryFormatter should work (havent tried yet).
However, Session states do support Xml serialization.
Suggestions/comments still welcome.
|
|
|
|
|
I tend to use binary serialization for several reasons:
1) Size. Binary < XML < Soap
If you have a lot of data, the difference can be "significant" and result in quicker load times. For example, Bin: 1.4Mb, XML: 2.5Mb, Soap: 9.4Mb
2) The XmlSerializer type will only serialize public data fields or private data exposed by public properties. Private data not exposed from properties will be ignored.
This is way too easy to forget, and can cause some very odd problems later.
|
|
|
|
|
Thanks for your reply.
Currently I am receiving an Xml which I an deserializing into a custom class. This custom class contains the [Serializable] attribute and also implements the ISerializable interface (probably extra work i did not need to do). The properties of this class contains the [XmlElement] and [XmlAttribute] attributes. Does this mean that this class can only be serialized/deserialized using the XmlSerializer only?
When I attempt to serialize/deserialize using the BinaryFormatter, I get the following error:
Type 'System.Xml.XmlNode' in Assembly 'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.
I also get this error when trying to set the ViewState item value to the object.
I get the feeling that the binarySerializer is trying to serialize an object that is already xmlserialized...
Is it possible for me to use mutlitple types of serializers on a single object?
|
|
|
|
|
If you are receiving an XML serialization, then the only thing you can deserialize it with is an XmlSerializer - it is entirly possible that the error you are getting is a reflection of this. I.e. that the XmlNode entries are private, not available as public properties and thus the tree can be saved by a XmlSerializer, but not with a BinaryFormatter since this will try to save all private variables as well. Since XmlNore does not appear to have a [Serializable]attribute, I think you are stuck with XmlSerializer.
You could use multiple type of serializer, but since each would contain the same data this would just increase the effort, without producing a benefit.
|
|
|
|
|
So we all know that exceptions for anything other than exceptional circumstances are a bad thing. Using them to control execution flow is criminal.
For fun, in a quick console app I created a loop that just created and caught exceptions. Anyone care to guess how many exceptions you can throw a second? (Typical development PC)
Regards,
Rob Philpott.
|
|
|
|
|
I'm guessing >100, <1000
I are troll
|
|
|
|