Here's some code I wrote a while back to do this and look at exceptions.
There's lots of junk in there, but the basic framework should work.
// ExceptionSurvey
// This utility looks through all the assemblies in a specified directory
// (or the current diretory if there is no specified directory), and checks
// to make sure all exception classes follow the specified guidelines.
//
// It verifies:
// 1) The exception name ends in "Exception"...
// 2) The exception implements the 3 standard constructors:
// class();
// class(string message);
// class(string message, Exception inner);
// 3) The exception implements the deserialization constructor:
// class(SerializationInfo info, StreamingContext context)
// 4) The exception has no public fields
// 5) If the exception has private fields, that it implements
GetObjectData()
// (there's no guarantee it does it *correctly*.
// 6) If the exception has private fields, it overrides the Message
property.
// 7) The exception is marked as serializable.
// This define controls whether the program tries to create, serialize, and
deserialize
// each exception class. Because of the assembly lookup rules, this will
only work if the
// exception checker is in the same directory as the assembly being checked.
// It's therefore turned off in the default case.
//#define LIVETEST
using System;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace ExceptionSurvey
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class ExceptionTester
{
int count = 0;
int errorCantSerialize = 0;
int errorNoInnerConstructor = 0;
int errorNoSerializationConstructor = 0;
int errorMissedFields = 0;
// test whether an exception can be serialized and deserialized by doing
it.
bool IsSerializable(Assembly assembly, Type type)
{
object o = null;
try
{
o = assembly.CreateInstance(type.Name);
}
catch (MissingMethodException e)
{
Console.WriteLine(e);
Console.WriteLine("Can't test serialization - no () constructor");
return(true);
}
Stream streamRead = null;
try
{
// try to serialize
try
{
Stream streamWrite = File.Create("MyRow.bin");
BinaryFormatter binaryWrite = new BinaryFormatter();
binaryWrite.Serialize(streamWrite, o);
streamWrite.Close();
}
catch (Exception e)
{
Console.WriteLine("Can't Serialize: {0}", e);
return false;
}
// try to deserialize
try
{
streamRead = File.OpenRead("MyRow.bin");
BinaryFormatter binaryRead = new BinaryFormatter();
object oout = binaryRead.Deserialize(streamRead);
}
catch (Exception e)
{
Console.WriteLine(" Can't Deserialize: {0}", e);
return false;
}
}
finally
{
streamRead.Close();
}
return(true);
}
bool IsException(Type type)
{
Type baseType = null;
while ((baseType = type.BaseType) != null)
{
if (baseType == typeof(System.Exception))
return(true);
type = baseType;
}
return(false);
}
public bool FindConstructor(Type t, string desc, params Type[] parameters)
{
bool retval = false;
ConstructorInfo ci = t.GetConstructor(BindingFlags.NonPublic |
BindingFlags.Public | BindingFlags.Instance, null, parameters, null);
string message = null;
if (ci != null)
{
if (ci.IsPublic)
retval = true;
else if (ci.IsPrivate)
message = "Private " + t.Name + desc;
else if (ci.IsFamily)
message = "Internal " + t.Name + desc;
}
else
{
message = "Missing " + t.Name + desc;
retval = false;
}
if (message != null)
Console.WriteLine(" " + message);
return retval;
}
void CheckException(Assembly assembly, Type t)
{
count++;
Console.WriteLine(" {0}", t);
// check to see that the exception is correctly named, with
// "Exception" at the end.
if (t.Name.LastIndexOf("Exception") + "Exception".Length !=
t.Name.Length)
{
Console.WriteLine(" Improper Name: {0}", t.Name);
}
// Does the exception have the 3 standard constructors?
// Default constructor
FindConstructor(t, "()");
// Constructor with a single string parameter
FindConstructor( t,
"(string message)",
typeof(System.String));
// Constructor with a string and an inner exception
if (!FindConstructor( t,
"(string message, Exception inner)",
typeof(System.String),
typeof(System.Exception)))
{
this.errorNoInnerConstructor++;
}
// check to see if the serialization constructor is present...
if (!FindConstructor( t,
"(SerializationInfo info, StreamingContext context)",
typeof(System.Runtime.Serialization.SerializationInfo),
typeof(System.Runtime.Serialization.StreamingContext)))
{
this.errorNoSerializationConstructor++;
}
// check to see if the type is market as serializable
if (!t.IsSerializable)
{
Console.WriteLine(" Exception isn't serializable - missing
[Serializable]?");
}
// The following block is #ifed out because it requires that the
exception
// checking exe be in the same directory as the assembly to be checked.
#if LIVETEST
// check to see whether this exception can be successfully serialized and
deserialized
if (!IsSerializable(assembly, t))
{
Console.WriteLine(" Not serializable");
this.errorCantSerialize++;
}
#endif
// check to see if there are any public fields. These should be
properties instead...
FieldInfo[] publicFields = t.GetFields(BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.Instance);
if (publicFields.Length != 0)
{
foreach (FieldInfo fieldInfo in publicFields)
{
Console.WriteLine(" public field {0} - should expose through
property", fieldInfo.Name);
}
}
// If this exception has any fields, check to
// make sure it has a version of GetObjectData. If not,
// it does't serialize those fields...
FieldInfo[] fields = t.GetFields(BindingFlags.DeclaredOnly |
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (fields.Length != 0)
{
if (t.GetMethod("GetObjectData", BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.Instance) == null)
{
this.errorMissedFields++;
Console.WriteLine(" Inherits GetObjectData()");
Console.WriteLine(" Doesn't serialize these fields");
foreach (FieldInfo field in fields)
{
Console.WriteLine(" {0}", field);
}
}
// Make sure Message is overridden
if (t.GetProperty("Message", BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.Instance) == null)
{
Console.WriteLine(" Exception doesn't override the Message
property");
}
}
Console.WriteLine();
}
void ProcessAssembly(FileInfo file)
{
try
{
Assembly a = Assembly.LoadFrom(file.FullName);
Console.WriteLine("File: {0}", file.FullName);
foreach (Type t in a.GetTypes())
{
if (IsException(t))
{
CheckException(a, t);
}
}
//Environment.Exit(0);
}
catch (Exception)
{
}
}
void PrintErrors()
{
Console.WriteLine("{0} Exceptions processed", count);
Console.WriteLine("{0} can't be serialized", errorCantSerialize);
Console.WriteLine("{0} can't be wrapped", errorNoInnerConstructor);
Console.WriteLine("{0} have no serialization constructor",
errorNoSerializationConstructor);
Console.WriteLine("{0} don't serialize fields", errorMissedFields);
}
static void Main(string[] args)
{
ExceptionTester tester = new ExceptionTester();
DirectoryInfo dirInfo = new DirectoryInfo(".");
foreach (FileInfo file in dirInfo.GetFiles("*.dll"))
{
tester.ProcessAssembly(file);
}
tester.PrintErrors();
}
}
}
--
Eric Gunnerson
Visit the C# product team at
http://www.csharp.net
Eric's blog is at
http://blogs.gotdotnet.com/ericgu/
This posting is provided "AS IS" with no warranties, and confers no rights.