|
Thanks Greeeg,
I would also like to use serialization if I could. As I mentioned in the below URL, the issue which blocks me from using serialization is, the information are stored in different objects/classes, I do not know how to aggregate them altogether. Any ideas?
http://www.codeproject.com/script/Forums/View.aspx?fid=1649&msg=2824797[^]
regards,
George
|
|
|
|
|
I think you have at least three options:
1. Create the document fully manually by looping the objects you want and add the information to the document you need
2. First serialize the objects, then loop through the xml documents created by serialization, read them and copy the relevant nodes to a single document
3. Create a generic collection (or nested collections if you need) and add your objects into that collection. After that, serialize it
I guess that if you have strict requirements for the xml 'format', serialization may not produce automatically the format you need. Also you can implement ISerializable on your objects, but that may be a longer way.
The need to optimize rises from a bad design.
My articles[ ^]
|
|
|
|
|
Thanks Mika,
1.
So, in my situation, you think generate the XML document manually is the best way?
2.
One more question about performance, I heard serialization is always faster than writing XML document manually, is that true?
regards,
George
|
|
|
|
|
1. I can't say it's the best option of those I listed, it depends on (all of) your requirements.
2. This should be true since serialization is normally a process done by framework and it's optimized. When writing your own document, you have your own custom MSIL code that is executed and it can hardly compete when it comes to speed.
The need to optimize rises from a bad design.
My articles[ ^]
|
|
|
|
|
Thanks Mika,
1.
My current confusion is the information which is needed to generate the XML file are from different Types. And I do not have a single type which aggregates all of the types. So, in my situation, the best option is to generate the XML manually?
2.
Mika Wendelius wrote: it depends on (all of) your requirements. What other requirements are needed? For example?
regards,
George
|
|
|
|
|
So do you mean that in the example Navaneeth wrote, you don't have Department class that contains all the other classes?
Your XML example in the original question had Deparment as a root element which held all the other elements.
|
|
|
|
|
Thanks Mika,
I decide to use similar way which Navaneeth wrote, I could wrote a upper level class to wrap all of the components, like department, teacher, clubs, etc.
How do you think of this solution?
regards,
George
|
|
|
|
|
|
You have two choice:
1. Create a function that will generate a string that will contain the xml. This method is the fastest and the most simple way to do it:
public class CClub
{
int m_id;
string m_name;
public string GenerateXml()
{
return
"<Club ID=\"" + m_id.ToString() + "\">\n" +
"<Name>" + m_name + "</Name>\n" +
"</Club>\n";
}
}
2. Use XmlDocument as told:
public class CClub
{
int m_id;
string m_name;
public void ReadXml(XmlElement element)
{
m_id = Convert.ToInt32(element.GetAttribute("Club"));
foreach (XmlNode node in element.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element &&
node.Name == "Club")
{
m_name = node.InnerText;
}
}
}
public void WriteXml(XmlNode parentNode)
{
XmlElement element = parentNode.OwnerDocument.CreateElement("Club");
parentNode.AppendChild(element);
element.SetAttribute("Club", m_id.ToString());
XmlElement elementName = parentNode.OwnerDocument.CreateElement("Name");
element.AppendChild(elementName);
elementName.InnerText = m_name;
}
}
The departement class should look like this:
public class CDepartment
{
CDepartmentInfo m_departmentInfo;
CClubs m_clubs;
CTeachers m_teachers;
public void ReadXml(XmlDocument element)
{
foreach (XmlNode node in element.ChildNodes)
{
if (node.NodeType == XmlNodeType.Element)
{
switch (node.Name)
{
case "DepartmentInfo":
m_departmentInfo = new CDepartmentInfo();
m_departmentInfo.ReadXml(node as XmlElement);
case "Clubs":
m_clubs = new CClubs();
m_clubs.ReadXml(node as XmlElement);
case "Teachers":
m_teachers = new CTeachers();
m_teachers.ReadXml(node as XmlElement);
}
}
}
}
public void WriteXml(XmlDocument document)
{
m_departmentInfo.WriteXml(document);
m_clubs.WriteXml(document);
m_teachers.WriteXml(document);
}
}
modified on Saturday, November 29, 2008 4:22 PM
|
|
|
|
|
Cool, solution, thanks darkzangel!
regards,
George
|
|
|
|
|
You can use XMLSerialization to do this. It makes your code more cleaner than creating XML using XMLDocument .
All you need is to create types for representing DepartmentInfo, Club and Teacher. It could be something like the following
public class DepartmentInfo
{
public DepartmentInfo(int id,string location,string type) {
this.Id = id;
this.Location = location;
this.Type = type;
}
public DepartmentInfo() {
}
[XmlAttribute("Id")]
public int Id { get; set; }
public string Location { get; set; }
public string Type { get; set; }
}
public class Club
{
public Club(int id,string name) {
this.Id = id;
this.Name = name;
}
public Club() {
}
[XmlAttribute("Id")]
public int Id { get; set; }
public string Name { get; set; }
}
public class Teacher
{
public Teacher(int id,string name,string major) {
this.Id = id;
this.Name = name;
this.Major = major;
}
public Teacher() {
}
[XmlAttribute("Id")]
public int Id { get; set; }
public string Name { get; set; }
public string Major { get; set; }
}
Now you need a Department type which has references to all the above shown types.
[XmlRoot("Department")]
public class Department
{
public Department(DepartmentInfo info,Club[] clubs,Teacher[] teachers) {
this.DepartmentInfo = info;
this.Clubs = clubs;
this.Teachers = teachers;
}
public Department() {
}
[XmlElement("DepartmentInfo")]
public DepartmentInfo DepartmentInfo { get; set; }
[XmlArray("Clubs")]
public Club[] Clubs { get; set; }
[XmlArray("Teachers")]
public Teacher[] Teachers { get; set; }
} You can serialize the Department class to get the specified XML. Here is how you do in a console application.
static void Main(string[] args) {
Club[] clubs = { new Club(200, "Football"), new Club(201, "Basketball") };
Teacher[] teachers = { new Teacher(300, "Thomas", "Algorithm"), new Teacher(301, "Zhou", "Linear Programming") };
Department department = new Department(new DepartmentInfo(100,"San Jose", "Computer Science"), clubs, teachers);
XmlSerializer serializer = new XmlSerializer(typeof(Department));
serializer.Serialize(Console.Out, department);
Console.Read();
} This method works well and your code will look cleaner. But serialization is performance costly as it uses reflection to get details of the type. Manually writing XML using XMLTextWriter or XMLDocument will give you better performance than this. Choosing the method is completly depends on your situation.
Hope this helps
|
|
|
|
|
Thanks Navaneeth!
I like your solution!
regards,
George
|
|
|
|
|
Hello All ,
I have one question... Does anybody know where I can download a copy of the Microsoft Visual C# User Manual. The one that comes with the IDE (Vis. Studio) is crap, it has broken links throughout the whole thing, and even when I choose to view online help it still has broken links. Is there a downloadable version of the C# full documentation? I only want C#.
j.t.
|
|
|
|
|
At least MSDN Express library is here[^]. There may also be other separate downloads on MSDN.
The need to optimize rises from a bad design.
My articles[ ^]
|
|
|
|
|
BTW: That IS the user manual.
|
|
|
|
|
Thank you both for your help I apologise if I came across as really rude in my original post, I only just realised as I re-read my original post.
Regards,
j.t.
j.t.
|
|
|
|
|
|
string pattern = @"((https?|ftp|gopher|telnet|file|notes|ms-help) //)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)"
Ahsan Ullah
Senior Software Engineer
MCTS 2.0
|
|
|
|
|
Thank you both for your answers and code though I only have one problem now, where would I put that code you just gave me? Or, how would I use it?
Regards,
j.t.
j.t.
|
|
|
|
|
A simple example would be:
MatchCollection mathes = Regex.Matches(textContent, "(http://[\w\.\?\&]+\w)");
That would give you a collection of matches for (most of) the URLs in the text. Each match contains information about where in the string it was found and the actual URL that was found.
Now, you would use your mad google skillz to find a more advanced regular expression for matching an URL.
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
you could also have a look at boost regex - it comes with some examples of parsing url's
'g'
|
|
|
|
|
I'm currently working on a c# project that need winsock in it. WebClient wasn't enought powerfull for my kind of application. So, I writed from scratch all the code to get all thing in my project with a custom webclient. Everything work fine, but I want to improve my code. One of my problem is a function that read byte from the recv function (recv is a c++ winsock function) and then send it to a stream to eventually get an array of byte (byte[]). If you take a closer look to my code, you will see that I copy twice the data. The first time, I make the convertion from byte* (IntPtr receiveBuff) to byte[] and then, I copy again those data to the stream with mem.Write(). I will like to only to it once. Doesn't any body know a better way to do this so I only have to make one copy of my data?
[DllImport("Ws2_32.dll")]
public static extern int recv(SOCKET s, byte* buf, int len, int flags);
public unsafe byte[] RecvAsBytes()
{
MemoryStream mem = new MemoryStream();
int receivedLen;
IntPtr receiveBuff = Marshal.AllocHGlobal(1024);
byte[] receiveBuff2 = new byte[1024];
while ((receivedLen = recv(socket, (byte*)receiveBuff, 1024, 0)) != 0)
{
Marshal.Copy(receiveBuff, receiveBuff2, 0, receivedLen);
mem.Write(receiveBuff2, 0, receivedLen);
}
Marshal.FreeHGlobal(receiveBuff);
return mem.ToArray();
}
|
|
|
|
|
Hi,
the way I usually transfer large amounts of data between a managed (C#) app and some unmanaged (C) code, is as follows:
1. have the managed code allocate a buffer of sufficient size; it could be a byte array in your case.
2. Use GCHandle class to first pin it down, then obtain a pointer to it.
3. Pass the pointer to the native code to get it read and/or written to.
4. Upon return, free the GCHandle and start using the buffer in the managed world.
In summary: no extra copies are made, and Marshal and MemoryStream classes are avoided.
Hope this helps.
|
|
|
|
|
It didn't help that much. Actually, I wasted more time trying to understand why I should use GCHandler instead of Marshal.AllocHGlobal, lol.
I finally figured out a much better way to do that. The only problem if it's problem is that I still use MemoryStream. The reason why I still use it is because I don't have any idea of the size of the received data. This function is used to receive both: html code and image data. The image size can be as large as 1Mb and my application is multithread. So think about that, allocating a 1Mb each time I want to receive data! I want to optimize my algo and make it as strong as I can, so it's a no no. There is still an another way to go with a pool of 1024 bit buffer and a stack, but this will need much more code and time to develop. Maybe one day... But for now, here is my improved code:
public unsafe byte[] RecvAsBytes()
{
MemoryStream mem = new MemoryStream();
int len;
byte[] buffer = new byte[1024];
fixed (byte* ptrBuffer = buffer)
{
while ((len = NativeImport.recv(socket, ptrBuffer, 1024, 0)) != 0)
mem.Write(buffer, 0, len);
}
return mem.ToArray();
}
|
|
|
|
|
Hi,
1.
your code contains two copy operations that add to the RAM footprint and the CPU load:
first you copy data from buffer to mem, then from mem to the final byte array.
(I checked with Reflector: MemoryStream.ToArray creates a whole new array and copies all the data)
2.
there is no need for a memory stream at all. You could:
- create a list of byte arrays;
- allocate a new byte[1024] array inside the while loop, and add these buffers to the a list;
- when that while loop finishes, add together all the sizes of the partial buffers, allocate a new byte[] of total size, then copy each partial buffer directly into the final buffer. You might use Array.Copy to do that, again inside a loop (I suggest a foreach).
Doing so eliminates half of the copy operations without costing more RAM footprint.
3.
Do you really need the possibly huge single byte array as a result? if not, you could forgo all copying. You might return the list of partial byte arrays, or an object that allows to enumerate the data. It all depends on the consumer of RecvAsBytes().
4.
If you really want the total byte array: if the data is originating from a web server, you may know the total size of the data beforehand; have a look at WebResponse.ContentLength; so you could allocate the final array at once, and fill it in your existing while loop.
5.
BTW: in that case you also can get a data stream directly (WebResponse.GetResponseStream). If your data is not coming from a WebResponse object, maybe you should consider modeling it after WebResponse.
6.
Your "fixed" statement and the GCHandle I suggested basically serve the same purpose; your solution is quite acceptable; the main difference is GCHandle does not require the "unsafe" switch, fixed does.
Cheers.
|
|
|
|
|