|
I
saw a post on oh null! that talks about how you can evaluate
expressions within the immediate window, whether you're simply
retrieving a variable or performing a calculation on multiple
variables. I personally like to do all of this in the Watch Window
because I can have an easy history of what variables I've interrogated.
Like the immediate window, you can call Methods and display the
results, but since methods can change state, they will not execute
automatically after you step into a new line of code, but there is a
nice little refresh button that will re-execute your method call.
As I understand it, the watch window is a wrapper around the simpler
functionality of the immediate window, so it also supports
Intellisense. But there are some things that you can only do in the
immediate window, like the .load [dll] command which lets you import
another assembly for your use, which is pretty damn slick. I've only
ever really used that feature in one scenario: to load the Son of
Strike assembly which helps you get detailed information on your
executable (very detailed call stack info, very granular heap
information, but kind of hard to use). Another cool thing you can do in your immediate window:
Declare new variables. Those variables will have the same scope as the
current breakpoint in execution, but the ability opens the doors to
some neat possibilities. For instance, you could declare a new
variable, copy a subset of information from your current in scope
variables and then use my Xml Utility Methods to copy your new object
out to disk! I'm not quite sure why you would need to do that, but its
nice to be able to!
With my work, I regularly
deal with obscene amounts. Of course, our users demand that this
information loads instantly and without running out of memory. So
optimizing our data storage objects for time and memory constraints is
incredibly important. So far, I think I've done a pretty good job,
because I can load 125 million data points in a shade over 3 seconds
(using a database to store some of this data flew out the window a
while ago). But getting to this point has been an interesting journey.
Doing quick prototyping of prospective storage mechanisms has been
incredibly important and I thought I'd share some of the utility
methods/classes I've created to speed up the process. The first piece of code is incredibly similar to my StopwatchWriter
Class. Instead of starting and stopping a Stopwatch, we're asking the
garbage collector how much total memory is being used (in bytes),
before and after you instantiate an object (or a whole set of objects)
public class MemoryWriter : IDisposable
{
long _startMem;
string _text;
public MemoryWriter(string text)
{
_text = text + " - ";
_startMem = GC.GetTotalMemory(true);
}
public void Dispose()
{
Console.WriteLine("mem: " + _text + (GC.GetTotalMemory(true) - _startMem).ToString());
}
}
Usage looks like:
using (new MemoryWriter("CrazyBigObject"))
{
CrazyBigObject myCrazyBigObject = LoadCrazyBigObject(42);
}This
is the most accurate way of figuring out how much memory a specific
object is taking up in memory. But there is a limitation to this method
if you're using it in a multi-threaded application, such as a Win Form
because another running thread could dereference objects on the heap after you've instantiated your MemoryWriter
, but before its been disposed. I prefer to only use this class in
small throw away console applications, to make my results as accurate
as possible. Sometimes though, you'll find yourself looking at
an object in someone else's code and you want to easily find out how
much memory its taking up, but the object in question is "built" over
several methods along with several other objects that you don't care
about. Which makes it impossible to use theMemoryWriter Class. You can
use a memory profiling application to do this, but I've found that they
are notoriously hard to pick up and use. And due to the nature of how
they work, they take ages to work because they have to take a snapshot
before and after the code you care about (i.e. copy your 700MB object
heap twice and then "diff" the two heaps). So I've wrote two small
methods that serialize the object to a stream and then return the
length of the stream. Note: This is approximately how much data the
object is holding in memory. It may besignificantly less than how much
space it takes up on the heap. Case in point: Dictionary<K, V>
takes up much more space in memory than it does when serialized.That's because it only serialized the key value pairs and it re-hydrates the dictionary on deserialization. Nor will it reflect the size of any properties on your object that are marked with the NonSerialized attribute. So it is far from perfect, but it helps give you an idea with out the pain of using a memory profiler
. You can use these methods by setting a break point and calling them
in your watch window (I prefer doing that over the immediate window). /// <summary>
/// Returns a rough approximation of the size of an object /// (including ALL objects in/directly referenced by the object)
/// </summary>
public static long ApproxSize(object obj)
{
BinaryFormatter formatter = new BinaryFormatter();
long length;
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, obj);
stream.Seek(0, SeekOrigin.Begin);
length = stream.Length;
}
return length;
}
Sometimes though, your object is very large and serializing the object in memory will cause an OutOfMemory
Exception. So use the below method instead, it serializes the object to
disk and gives you the size of the file (and deletes the file after its
done). /// <summary> /// Returns the approximate size of very large objects /// (time intensive) in bytes. /// </summary>
public static long ApproxSizeLarge(object obj)
{
FileInfo info = new FileInfo(@"c:\approxSizeTemp");
BinaryFormatter formatter = new BinaryFormatter();
using (StreamWriter writer = new StreamWriter(@"c:\approxSizeTemp"))
{
formatter.Serialize(writer.BaseStream, obj);
}
long length = info.Length;
info.Delete();
return length;
}
So I was never really expecting to make much money from my AdSense advertisements, if I made $10 in a year, I'd be happy. But perhaps I've only made 80 cents thus far because Google is serving absurd ads like:  What AdWords did these people buy that is displayed on my site talking about Microsoft Technologies? Is this some sort of joke perpetrated the FOSS Commie Zealots? My content might be a little crappy ( or not) but C#, WPF and LINQ are simply bad-ass.
I'm sure there are plenty of you out there who have your boss hankering
to use some of that "Xml Stuff". Sometimes we get sheltered in our own
little world and haven't actually had to work with a whole lot of xml
data that wasn't already wrapped up by the Project Settings object
created by Visual Studio. So naturally, you'd probably go to the " tubes"
and search for some additional information. Undoubtedly, you will run
across pages telling you how to construct some Xml in C# by creating a
new XmlDocument and adding XmlNode children which will have attributes
and subnodes and namespaces, ad infinitum. And you'll realize you now have
some of the world's fugliest code. So you decide, "oh, well xml is
really similar to html, I'll just build it using a StringBuilder" and
you end up with slightly less fugly code, that is until you try to read
it back in. These
methods are completely unnecessary. PUT DOWN THE XMLNODE AND STEP AWAY
FROM THE STRINGBUILDER. Slowly move your hand to the mouse and scroll
down to read about the easiest way to write and read Xml in the .net framework. Ok,
quick show of hands: who thinks working with simple .net business model
objects is brain dead easy? Alright, if your hand isn't up, you are
beyond hope, please leave now. Of course, working with simple objects
is about the simplest exercise for code next to "Hello World". If you
can create a .net object that models the xml you want to store, you are 95% done with outputting well formed Xml. Example: If I wanted to store information about a few people and their pets I would create three classes: public class PetClub { public List<Person> Members { get; set; } }
public class Person { public string Name { get; set; } public List<Pet> Pets { get; set; } }
public class Pet { public string Name { get; set; } public string Type { get; set; } } To
get an Xml representation of an instance of PetClub, all you have to do
is use the XmlSerializer found in the System.Xml.Serialization
namespace. I've wrapped up all the necessary code into a short utility
method. public static string ConvertToXml(object item) { XmlSerializer xmlser = new XmlSerializer(item.GetType()); using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { xmlser.Serialize(ms, item); UTF8Encoding textconverter = new UTF8Encoding(); return textconverter.GetString(ms.ToArray()); } } Simply calling: ConvertToXml(myPetClubInstance) will spit back the following xml: <PetClub xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Members> <Person> <Name>Jon</Name> <Pets> <Pet> <Name>Chester</Name> <Type>Savannah Cat</Type> </Pet> <Pet> <Name>Abby</Name> <Type>Domestic Miniature Panther</Type> </Pet> </Pets> </Person> <Person> <Name>Dan</Name> <Pets> <Pet> <Name>Lucy</Name> <Type>Semi-sweet Chocolate Lab</Type> </Pet> </Pets> </Person> </Members> </PetClub>
At this point you might be saying: "That is cool and all, Jon, but this
looks like a lot of xml to be outputting for such little actual data.
And what if I want to have more control over xml element naming". Dear
friend, let not your heart be troubled for there is help on the way. By
adding some simple Property Attributes to our classes we can completely
change how our xml is constructed. We can have the object in whatever
form is most convienient for our program while still allowing us to
interoperate with an xml document created by a different application
with a different idea of what good names are.
Changing our two classes to:
public class Person { [XmlElement("FirstName")] public string Name { get; set; } public List<Pet> Pets { get; set; } }
public class Pet { [XmlAttribute("Name")] public string Name { get; set; } [XmlAttribute("Breed")] public string Type { get; set; } }
Will output this xml:
<PetClub xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Members>
<Person>
<FirstName>Jon</FirstName>
<Pets>
<Pet Name="Chester" Breed="Savannah Cat" />
<Pet Name="Abby" Breed="Domestic Miniature Panther" />
</Pets>
</Person>
<Person>
<FirstName>Dan</FirstName>
<Pets>
<Pet Name="Lucy" Breed="Semi-sweet Chocolate Lab" />
</Pets>
</Person>
</Members>
</PetClub>
Pretty simple, huh? Can you imagine how difficult it would be to
make these changes via XmlNodes or a StringBuilder? There are about 10
other property attributes available for xml
serialization, including the very useful XmlIgnore() attribute which
makes the appropriate property not serialized. I'll leave the rest of
the research up to you.
And I almost forgot, to read your xml back into an object use the following method:
public static T FromXml<T>(string xml) { XmlSerializer xmlser = new XmlSerializer(typeof(T)); using (System.IO.StringReader sr = new System.IO.StringReader(xml)) { return (T)xmlser.Deserialize(sr); } }
Sample Code - XmlSerializerSample.cs (2.33 KB)
Well, as you can tell I've got a new DasBlog theme I created myself. I'm not the most artistic person in the world, but I'm happy with what I've accomplished. Good lord did it take a long time, its been a while since I've pounded out HTML and CSS, but I'm glad to have it fresh in my head again but I'm totally disgusted at how differently IE and Firefox render, what a gigantic waste of time. Have a good week!
It really does shock and amaze me how many developers get through the day without knowing the wonders of the Exceptions Dialog box. You can access it via Debug>Exceptions or you can hit Ctrl-Alt-E. What this dialog box allows you do is to pick a set of exceptions (or all of them for that matter) and the debugger will automatically break when the exception is thrown. This allows you to inspect your call stack and interrogate your variables to determine the state of your application when the exception occurred. No longer do you have to look through an error message to find a line number and start setting break points. This becomes especially helpful if the error is occurring in a gigantic loop and your not sure how many times the loop executes before it runs into a null reference exception. It breaks automatically and voila, you can easily see all the variables that are associated with your null object (or whatever the error may be). Sometimes you'll be responsible for code, that for one reason or another uses exception catching/handling as a normal part of code flow. This usually is considered a bad practice but sometimes you don't have a choice under the circumstances. When that happens, it is very easy to turn off custom typed exceptions, just click the "Add..." button and type in the fully qualified name of the exception you don't want to see every time it is thrown. As you can see in my screenshot, I've done this with the Sybase.Data.AseClient.AseException exception. I hope this helps speed up any future debugging.
I just found this site off of dotnetkicks, and it looks like a great reference site for information on patterns and anti-patterns http://sourcemaking.com/
|
|
Nitriq is a Code Analysis Tool for .Net Developers. It helps you visualize your code and quickly find types and methods that need refactoring.
It is currently in a free public beta, but will have reasonable prices once the bugs are worked out.
I'll be using this blog to talk about .Net, C#, WPF, ASP.NET, Nitriq and MicroISVs.
RSS
Tags
Archive
| November, 2009 (2) |
| October, 2009 (5) |
| September, 2009 (1) |
| August, 2009 (1) |
| July, 2009 (1) |
| June, 2009 (1) |
| May, 2009 (1) |
| April, 2009 (2) |
| March, 2009 (1) |
| February, 2009 (2) |
| January, 2009 (1) |
| October, 2008 (1) |
| September, 2008 (1) |
| August, 2008 (1) |
| July, 2008 (2) |
| June, 2008 (2) |
| May, 2008 (2) |
| March, 2008 (2) |
| February, 2008 (8) |
| January, 2008 (4) |
| December, 2007 (6) |
| November, 2007 (2) |
|