Must anything in particular be done to add a new tool to the mcs/tools
directory?
I've been working on a reflection tool which would display most of the
information available through System.Type for a given type. I call it
`type-reflector', and it's attached.
To use it, just specify the type to view on the command line with the
`-S' (show all) and `-v' (verbose) options specified.
It currently doesn't display *all* System.Type information due to
deficiencies with Mono. Some reflection attributes aren't present in
Mono (such as Assembly.EscapedCodeBase), while others generate run-time
exceptions when invoked (Assembly.ToString() is currently giving me
problems). All information available through the public Attributes of
the System.Type and related classes can be viewed by compiling with "-D
MONO_BROKEN" and executing with `-K' (show broKen attributes).
It also provides a simple way to view the values of enumeration
constants. (I was never able to make `EnumCheck.exe' work, so this
provides an alternative.) For an example, run the program as:
mono type-reflector.exe -Afv type-reflector.exe TestEnum
and look for "Enumeration Value" in the output.
Thanks,
- Jon
//
// type-reflector.cs:
// Finds types and (optionally) shows reflection information about
// the types.
//
// Author: Jonathan Pryor ([EMAIL PROTECTED])
//
// (C) 2002 Jonathan Pryor
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to
// do so, subject to the following conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// #define TRACE
using System;
using System.Collections;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
namespace Testing
{
interface IFoo {}
interface IBar {}
interface IBaz {}
delegate void FooEventHandler ();
[CLSCompliant(false)]
class TestClass : IFoo, IBar, IBaz {
private int PrivateField;
protected float ProtectedField;
public double PublicField;
internal long InternalField;
public TestClass (short s) {PublicField = 3.14;}
protected TestClass (long l) {ProtectedField = 2.71F;}
private TestClass (int i) {PrivateField = 13;}
internal TestClass (float f) {InternalField = 64;}
public int PublicGetSet {
get {return 0;}
set {PublicField = value;}
}
protected short ProtectedGetter {
get {return -1;}
}
private char PrivateSetter {
set {PrivateField = value;}
}
internal float InternalProperty {
get {return ProtectedField;}
set {ProtectedField = value;}
}
public event FooEventHandler PubFoo;
protected event FooEventHandler ProFoo;
private event FooEventHandler PrivFoo;
internal event FooEventHandler IntFoo;
public short PublicMethod (short s) {return s;}
private int PrivateMethod (int i) {return i;}
protected long ProtectedMethod (long l) {return l;}
internal float InternalMethod (float f) {return f;}
}
enum TestEnum {
Foo,
Bar,
Baz,
Qux,
Quux
}
}
namespace Mono.TypeReflector
{
public delegate void BaseTypeEventHandler (object sender, BaseTypeEventArgs e);
public delegate void TypeEventHandler (object sender, TypeEventArgs e);
public delegate void InterfacesEventHandler (object sender,
InterfacesEventArgs e);
public delegate void FieldsEventHandler (object sender, FieldsEventArgs e);
public delegate void PropertiesEventHandler (object sender,
PropertiesEventArgs e);
public delegate void EventsEventHandler (object sender, EventsEventArgs e);
public delegate void ConstructorsEventHandler (object sender,
ConstructorsEventArgs e);
public delegate void MethodsEventHandler (object sender, MethodsEventArgs e);
public class BaseTypeEventArgs : EventArgs {
private Type _base;
internal BaseTypeEventArgs (Type type)
{
_base = type;
}
public Type BaseType {
get {return _base;}
}
}
public class TypeEventArgs : EventArgs {
private Type _type;
internal TypeEventArgs (Type type)
{
_type = type;
}
public Type Type {
get {return _type;}
}
}
public class InterfacesEventArgs : EventArgs {
private Type[] _interfaces;
internal InterfacesEventArgs (Type[] interfaces)
{
_interfaces = interfaces ;
}
public Type[] Interfaces {
get {return _interfaces;}
}
}
public class FieldsEventArgs : EventArgs {
private FieldInfo[] _fields;
internal FieldsEventArgs (FieldInfo[] fields)
{
_fields = fields;
}
public FieldInfo[] Fields {
get {return _fields;}
}
}
public class PropertiesEventArgs : EventArgs {
private PropertyInfo[] _props;
internal PropertiesEventArgs (PropertyInfo[] properties)
{
_props = properties;
}
public PropertyInfo[] Properties {
get {return _props;}
}
}
public class EventsEventArgs : EventArgs {
private EventInfo[] _events;
internal EventsEventArgs (EventInfo[] events)
{
_events = events;
}
public EventInfo[] Events {
get {return _events;}
}
}
public class ConstructorsEventArgs : EventArgs {
private ConstructorInfo[] _ctors;
internal ConstructorsEventArgs (ConstructorInfo[] ctors)
{
_ctors = ctors;
}
public ConstructorInfo[] Constructors {
get {return _ctors;}
}
}
public class MethodsEventArgs : EventArgs {
private MethodInfo[] _methods;
internal MethodsEventArgs (MethodInfo[] methods)
{
_methods = methods;
}
public MethodInfo[] Methods {
get {return _methods;}
}
}
public class TypeDisplayer {
private bool showBase = false;
private bool showConstructors = false;
private bool showEvents = false;
private bool showFields = false;
private bool showInterfaces = false;
private bool showMethods = false;
private bool showProperties = false;
private bool showTypeProperties = false;
private bool showInheritedMembers = false;
private bool verboseOutput = false;
private bool flattenHierarchy = false;
private bool showNonPublic = false;
private bool showMonoBroken = false;
public bool ShowBase {
get {return showBase;}
set {showBase = value;}
}
public bool ShowConstructors {
get {return showConstructors;}
set {showConstructors = value;}
}
public bool ShowEvents {
get {return showEvents;}
set {showEvents = value;}
}
public bool ShowFields {
get {return showFields;}
set {showFields = value;}
}
public bool ShowInterfaces {
get {return showInterfaces;}
set {showInterfaces = value;}
}
public bool ShowMethods {
get {return showMethods;}
set {showMethods = value;}
}
public bool ShowProperties {
get {return showProperties;}
set {showProperties = value;}
}
public bool ShowTypeProperties {
get {return showTypeProperties;}
set {showTypeProperties = value;}
}
public bool ShowInheritedMembers {
get {return showInheritedMembers;}
set {showInheritedMembers = value;}
}
public bool ShowNonPublic {
get {return showNonPublic;}
set {showNonPublic = value;}
}
public bool ShowMonoBroken {
get {return showMonoBroken;}
set {showMonoBroken = value;}
}
public bool FlattenHierarchy {
get {return flattenHierarchy;}
set {flattenHierarchy = value;}
}
public bool VerboseOutput {
get {return verboseOutput;}
set {verboseOutput = value;}
}
private static BindingFlags bindingFlags =
BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.Static;
public void Parse (Type type)
{
BindingFlags bf = bindingFlags;
if (FlattenHierarchy)
bf |= BindingFlags.FlattenHierarchy;
if (ShowInheritedMembers)
bf &= ~BindingFlags.DeclaredOnly;
if (ShowNonPublic)
bf |= BindingFlags.NonPublic;
Type (type);
BaseType (type.BaseType);
Interfaces (type.GetInterfaces ());
Fields (type.GetFields(bf));
Constructors (type.GetConstructors(bf));
Properties (type.GetProperties(bf));
Events (type.GetEvents(bf));
Methods (type.GetMethods(bf));
}
private void Type (Type t)
{
TypeEventArgs ea = new TypeEventArgs (t);
try {
OnType (ea);
} finally {
if (ReceiveTypes != null)
ReceiveTypes (this, ea);
}
}
protected virtual void OnType (TypeEventArgs e) {}
private void BaseType (Type t)
{
if (ShowBase) {
BaseTypeEventArgs ea = new BaseTypeEventArgs (t);
try {
OnBaseType (ea);
} finally {
if (ReceiveBaseType != null)
ReceiveBaseType (this, ea);
}
}
}
protected virtual void OnBaseType (BaseTypeEventArgs e) {}
private void Interfaces (Type[] i)
{
if (ShowInterfaces) {
InterfacesEventArgs ea = new InterfacesEventArgs (i);
try {
OnInterfaces (ea);
} finally {
if (ReceiveInterfaces != null)
ReceiveInterfaces (this, ea);
}
}
}
protected virtual void OnInterfaces (InterfacesEventArgs e) {}
private void Fields (FieldInfo[] f)
{
if (ShowFields) {
FieldsEventArgs ea = new FieldsEventArgs (f);
try {
OnFields (ea);
} finally {
if (ReceiveFields != null)
ReceiveFields (this, ea);
}
}
}
protected virtual void OnFields (FieldsEventArgs e) {}
private void Properties (PropertyInfo[] p)
{
if (ShowProperties) {
PropertiesEventArgs ea = new PropertiesEventArgs (p);
try {
OnProperties (ea);
} finally {
if (ReceiveProperties != null)
ReceiveProperties (this, ea);
}
}
}
protected virtual void OnProperties (PropertiesEventArgs e) {}
private void Events (EventInfo[] e)
{
if (ShowEvents) {
EventsEventArgs ea = new EventsEventArgs (e);
try {
OnEvents (ea);
} finally {
if (ReceiveEvents != null)
ReceiveEvents (this, ea);
}
}
}
protected virtual void OnEvents (EventsEventArgs e) {}
private void Constructors (ConstructorInfo[] c)
{
if (ShowConstructors) {
ConstructorsEventArgs ea = new ConstructorsEventArgs
(c);
try {
OnConstructors (ea);
} finally {
if (ReceiveConstructors != null)
ReceiveConstructors (this, ea);
}
}
}
protected virtual void OnConstructors (ConstructorsEventArgs e)
{
}
private void Methods (MethodInfo[] m)
{
if (ShowMethods) {
MethodsEventArgs ea = new MethodsEventArgs (m);
try {
OnMethods (ea);
} finally {
if (ReceiveMethods != null)
ReceiveMethods (this, ea);
}
}
}
protected virtual void OnMethods (MethodsEventArgs e) {}
public event TypeEventHandler ReceiveTypes;
public event BaseTypeEventHandler ReceiveBaseType;
public event InterfacesEventHandler ReceiveInterfaces;
public event FieldsEventHandler ReceiveFields;
public event PropertiesEventHandler ReceiveProperties;
public event EventsEventHandler ReceiveEvents;
public event ConstructorsEventHandler ReceiveConstructors;
public event MethodsEventHandler ReceiveMethods;
}
public class IndentingTextWriter : TextWriter {
private TextWriter _writer;
private int indentLevel = 0;
private int indentSize = 4;
private bool needIndent = true;
private char indentChar = ' ';
public IndentingTextWriter (TextWriter writer)
{
_writer = writer;
}
public int IndentLevel {
get {return indentLevel;}
set {indentLevel = value;}
}
public int IndentSize {
get {return indentSize;}
set {indentSize = value;}
}
public char IndentChar {
get {return indentChar;}
set {indentChar = value;}
}
public void Indent ()
{
++IndentLevel;
}
public void Unindent ()
{
--IndentLevel;
}
protected bool NeedIndent {
get {return needIndent;}
set {needIndent = value;}
}
protected virtual void WriteIndent ()
{
NeedIndent = false;
Trace.WriteLine (String.Format(
"** WriteIndent: char='{0}',level={1},size={2}",
IndentChar, IndentLevel, IndentSize));
string indent = new string (IndentChar,
IndentLevel * IndentSize);
Write (indent);
}
protected override void Dispose (bool disposing)
{
if (disposing)
_writer.Close ();
}
public override System.Text.Encoding Encoding {
get {return _writer.Encoding;}
}
public override void Write (string value)
{
if (NeedIndent)
WriteIndent ();
_writer.Write (value);
}
public override void WriteLine ()
{
if (NeedIndent)
WriteIndent ();
_writer.WriteLine ();
NeedIndent = true;
}
public override void WriteLine (string value)
{
Trace.WriteLine (String.Format(
"** WriteLine: NeedIndent={0}", NeedIndent));
if (NeedIndent)
WriteIndent ();
_writer.WriteLine (value);
NeedIndent = true;
}
}
public class Indenter : IDisposable {
private IndentingTextWriter _writer;
// private int level;
public Indenter (IndentingTextWriter writer)
: this (writer, 1)
{
}
public Indenter (IndentingTextWriter writer, int level)
{
_writer = writer;
// XXX: _writer.IndentLevel += level;
_writer.Indent ();
}
public void Dispose ()
{
// XXX: _writer.IndentLevel -= level;
_writer.Unindent ();
Trace.WriteLine (String.Format(
"** Disposing; indentlevel={0}",
_writer.IndentLevel));
}
}
class VerboseTreeTypeDisplayer : TypeDisplayer {
private IndentingTextWriter _writer;
public VerboseTreeTypeDisplayer (TextWriter writer)
{
_writer = new IndentingTextWriter (writer);
_writer.IndentChar = ' ';
_writer.IndentSize = 2;
}
public IndentingTextWriter Writer {
get {return _writer;}
}
private void PrintMemberInfo (MemberInfo mi)
{
Writer.WriteLine ("DeclaringType={0}", mi.DeclaringType);
Writer.WriteLine ("MemberType={0}", mi.MemberType);
Writer.WriteLine ("Name={0}", mi.Name);
Writer.WriteLine ("ReflectedType={0}", mi.ReflectedType);
/*
* Not liked by Constructors: on type MethodsEventHandler
Writer.WriteLine ("GetCustomAttributes():");
using (Indenter n1 = new Indenter (Writer)) {
object[] attrs = mi.GetCustomAttributes (true);
foreach (object a in attrs)
Writer.WriteLine (a);
}
*/
}
protected override void OnType (TypeEventArgs e)
{
string t = null;
if (e.Type.IsClass)
t = "class";
else if (e.Type.IsEnum)
t = "enum";
else if (e.Type.IsValueType)
t = "struct";
else if (e.Type.IsInterface)
t = "interface";
else
t = "type";
Writer.WriteLine (String.Format ("{0,-11}{1}", t,
e.Type.ToString()));
using (Indenter n1 = new Indenter (Writer)) {
if (ShowTypeProperties) {
Writer.WriteLine ("System.Type Properties:");
using (Indenter n2 = new Indenter (Writer))
PrintType (e.Type);
}
}
}
protected string PrintEnumValue (Type enumType, object value)
{
return Enum.Format(enumType, value, "f") + " (" + value + ")";
}
protected void PrintType (Type i)
{
PrintMemberInfo (i);
Writer.WriteLine ("Delimiter={0}", Type.Delimiter);
if (ShowMonoBroken)
Writer.WriteLine ("EmptyTypes={0}",
Type.EmptyTypes.ToString());
Writer.WriteLine ("FilterAttribute={0}", Type.FilterAttribute);
Writer.WriteLine ("FilterName={0}", Type.FilterName);
Writer.WriteLine ("FilterNameIgnoreCase={0}",
Type.FilterNameIgnoreCase);
if (ShowMonoBroken)
Writer.WriteLine ("Missing={0}", Type.Missing);
if (ShowMonoBroken)
Writer.WriteLine ("Assembly={0}", i.Assembly);
using (Indenter n1 = new Indenter (Writer)) {
if (ShowMonoBroken)
Writer.WriteLine ("CodeBase={0}",
i.Assembly.CodeBase);
Writer.WriteLine ("EntryPoint={0}",
i.Assembly.EntryPoint);
#if MONO_BROKEN
if (ShowMonoBroken)
Writer.WriteLine ("EscapedCodeBase={0}",
i.Assembly.EscapedCodeBase);
#endif
Writer.WriteLine ("Evidence={0}", i.Assembly.Evidence);
if (ShowMonoBroken)
Writer.WriteLine ("FullName={0}",
i.Assembly.FullName);
#if MONO_BROKEN
if (ShowMonoBroken)
Writer.WriteLine ("GlobalAssemblyCache={0}",
i.Assembly.GlobalAssemblyCache);
#endif
Writer.WriteLine ("Location={0}", i.Assembly.Location);
}
if (ShowMonoBroken)
Writer.WriteLine ("AssemblyQualifiedName={0}",
i.AssemblyQualifiedName);
Writer.WriteLine ("Attributes={0}",
PrintEnumValue (typeof(TypeAttributes), i.Attributes));
Writer.WriteLine ("BaseType={0}", i.BaseType);
Writer.WriteLine ("DeclaringType={0}", i.DeclaringType);
Writer.WriteLine ("DefaultBinder={0}", Type.DefaultBinder);
Writer.WriteLine ("FullName={0}", i.FullName);
Writer.WriteLine ("GUID={0}", i.GUID);
Writer.WriteLine ("HasElementType={0}", i.HasElementType);
Writer.WriteLine ("IsAbstract={0}", i.IsAbstract);
Writer.WriteLine ("IsAnsiClass={0}", i.IsAnsiClass);
Writer.WriteLine ("IsArray={0}", i.IsArray);
Writer.WriteLine ("IsAutoClass={0}", i.IsAutoClass);
Writer.WriteLine ("IsAutoLayout={0}", i.IsAutoLayout);
Writer.WriteLine ("IsByRef={0}", i.IsByRef);
Writer.WriteLine ("IsClass={0}", i.IsClass);
Writer.WriteLine ("IsCOMObject={0}", i.IsCOMObject);
Writer.WriteLine ("IsContextful={0}", i.IsContextful);
Writer.WriteLine ("IsEnum={0}", i.IsEnum);
Writer.WriteLine ("IsExplicitLayout={0}", i.IsExplicitLayout);
Writer.WriteLine ("IsImport={0}", i.IsImport);
Writer.WriteLine ("IsInterface={0}", i.IsInterface);
Writer.WriteLine ("IsLayoutSequential={0}",
i.IsLayoutSequential);
Writer.WriteLine ("IsMarshalByRef={0}", i.IsMarshalByRef);
Writer.WriteLine ("IsNestedAssembly={0}", i.IsNestedAssembly);
Writer.WriteLine ("IsNestedFamORAssem={0}",
i.IsNestedFamORAssem);
Writer.WriteLine ("IsNestedPrivate={0}", i.IsNestedPrivate);
Writer.WriteLine ("IsNotPublic={0}", i.IsNotPublic);
Writer.WriteLine ("IsPointer={0}", i.IsPointer);
Writer.WriteLine ("IsPrimitive={0}", i.IsPrimitive);
Writer.WriteLine ("IsPublic={0}", i.IsPublic);
Writer.WriteLine ("IsSealed={0}", i.IsSealed);
Writer.WriteLine ("IsSerializable={0}", i.IsSerializable);
Writer.WriteLine ("IsSpecialName={0}", i.IsSpecialName);
Writer.WriteLine ("IsUnicodeClass={0}", i.IsUnicodeClass);
Writer.WriteLine ("IsValueType={0}", i.IsValueType);
Writer.WriteLine ("Module={0}", i.Module);
Writer.WriteLine ("Namespace={0}", i.Namespace);
Writer.WriteLine ("TypeHandle={0}", i.TypeHandle);
if (ShowMonoBroken)
Writer.WriteLine ("TypeInitializer={0}",
i.TypeInitializer);
Writer.WriteLine ("UnderlyingSystemType={0}",
i.UnderlyingSystemType);
}
protected override void OnInterfaces (InterfacesEventArgs e)
{
using (Indenter n = new Indenter (Writer)) {
Writer.WriteLine ("Interfaces:");
using (Indenter n2 = new Indenter (Writer)) {
foreach (Type i in e.Interfaces) {
Writer.WriteLine (i);
if (VerboseOutput) {
using (Indenter n3 = new
Indenter (Writer)) {
PrintType (i);
}
}
}
}
}
}
protected void PrintFieldInfo (FieldInfo f)
{
if (VerboseOutput) {
PrintMemberInfo (f);
Writer.WriteLine ("Attributes={0}",
PrintEnumValue (typeof(FieldAttributes),
f.Attributes));
Writer.WriteLine ("FieldHandle={0}", f.FieldHandle);
Writer.WriteLine ("FieldType={0}", f.FieldType);
Writer.WriteLine ("IsAssembly={0}", f.IsAssembly);
Writer.WriteLine ("IsFamily={0}", f.IsFamily);
Writer.WriteLine ("IsFamilyAndAssembly={0}",
f.IsFamilyAndAssembly);
Writer.WriteLine ("IsFamilyOrAssembly={0}",
f.IsFamilyOrAssembly);
Writer.WriteLine ("IsInitOnly={0}", f.IsInitOnly);
Writer.WriteLine ("IsLiteral={0}", f.IsLiteral);
Writer.WriteLine ("IsNotSerialized={0}",
f.IsNotSerialized);
Writer.WriteLine ("IsPinvokeImpl={0}",
f.IsPinvokeImpl);
Writer.WriteLine ("IsPrivate={0}", f.IsPrivate);
Writer.WriteLine ("IsPublic={0}", f.IsPublic);
Writer.WriteLine ("IsSpecialName={0}",
f.IsSpecialName);
Writer.WriteLine ("IsStatic={0}", f.IsStatic);
if (f.IsStatic && f.IsLiteral) {
Writer.Write ("Enumeration Value: ");
string s = Enum.Format (f.DeclaringType,
f.GetValue(null), "x");
Writer.WriteLine ("0x{0}", s);
}
/*
if (f.DeclaringType.IsEnum && f.IsStatic) {
Writer.Write ("Enumeration Value (2): ");
string s = Enum.Format (f.DeclaringType,
f.GetValue(null), "x");
Writer.WriteLine ("0x{0}", s);
}
*/
}
}
protected override void OnFields (FieldsEventArgs e)
{
using (Indenter n1 = new Indenter (Writer)) {
Writer.WriteLine ("Fields:");
using (Indenter n2 = new Indenter (Writer)) {
foreach (FieldInfo f in e.Fields) {
Writer.WriteLine (f);
using (Indenter n3 = new Indenter
(Writer)) {
PrintFieldInfo (f);
}
}
}
}
}
protected void PrintPropertyInfo (PropertyInfo p)
{
if (VerboseOutput) {
PrintMemberInfo (p);
Writer.WriteLine ("Attributes={0}",
PrintEnumValue (typeof(PropertyAttributes),
p.Attributes));
Writer.WriteLine ("CanRead={0}", p.CanRead);
Writer.WriteLine ("CanWrite={0}", p.CanWrite);
Writer.WriteLine ("IsSpecialName={0}",
p.IsSpecialName);
Writer.WriteLine ("PropertyType={0}", p.PropertyType);
}
}
protected override void OnProperties (PropertiesEventArgs e)
{
using (Indenter n1 = new Indenter (Writer)) {
Writer.WriteLine ("Properties:");
using (Indenter n2 = new Indenter (Writer)) {
foreach (PropertyInfo p in e.Properties) {
Writer.WriteLine (p);
using (Indenter n3 = new Indenter
(Writer)) {
PrintPropertyInfo (p);
}
}
}
}
}
protected void PrintEventInfo (EventInfo i)
{
if (VerboseOutput) {
PrintMemberInfo (i);
Writer.WriteLine ("Attributes={0}", PrintEnumValue
(typeof(EventAttributes), i.Attributes));
Writer.WriteLine ("EventHandlerType={0}",
i.EventHandlerType);
Writer.WriteLine ("IsMulticast={0}", i.IsMulticast);
Writer.WriteLine ("IsSpecialName={0}",
i.IsSpecialName);
}
}
protected override void OnEvents (EventsEventArgs e)
{
using (Indenter n1 = new Indenter (Writer)) {
Writer.WriteLine ("Events:");
using (Indenter n2 = new Indenter (Writer)) {
foreach (EventInfo i in e.Events) {
Writer.WriteLine (i);
using (Indenter n3 = new Indenter
(Writer)) {
PrintEventInfo (i);
}
}
}
}
}
private void PrintMethodBase (MethodBase mb)
{
PrintMemberInfo (mb);
Writer.WriteLine ("Attributes={0}",
PrintEnumValue (typeof(MethodAttributes),
mb.Attributes));
Writer.WriteLine ("CallingConvention={0}",
mb.CallingConvention);
Writer.WriteLine ("IsAbstract={0}", mb.IsAbstract);
Writer.WriteLine ("IsAssembly={0}", mb.IsAssembly);
Writer.WriteLine ("IsConstructor={0}", mb.IsConstructor);
Writer.WriteLine ("IsFamily={0}", mb.IsFamily);
Writer.WriteLine ("IsFamilyAndAssembly={0}",
mb.IsFamilyAndAssembly);
Writer.WriteLine ("IsFamilyOrAssembly={0}",
mb.IsFamilyOrAssembly);
Writer.WriteLine ("IsFinal={0}", mb.IsFinal);
Writer.WriteLine ("IsHideBySig={0}", mb.IsHideBySig);
Writer.WriteLine ("IsPrivate={0}", mb.IsPrivate);
Writer.WriteLine ("IsPublic={0}", mb.IsPublic);
Writer.WriteLine ("IsSpecialName={0}", mb.IsSpecialName);
Writer.WriteLine ("IsStatic={0}", mb.IsStatic);
Writer.WriteLine ("IsVirtual={0}", mb.IsVirtual);
Writer.WriteLine ("MethodHandle={0}", mb.MethodHandle);
}
protected void PrintConstructorInfo (ConstructorInfo c)
{
if (VerboseOutput) {
PrintMethodBase (c);
}
}
protected override void OnConstructors (ConstructorsEventArgs e)
{
using (Indenter n1 = new Indenter (Writer)) {
Writer.WriteLine ("Constructors:");
using (Indenter n2 = new Indenter (Writer)) {
foreach (ConstructorInfo c in e.Constructors) {
Writer.WriteLine (c);
using (Indenter n3 = new Indenter
(Writer)) {
PrintConstructorInfo (c);
}
}
}
}
}
protected void PrintMethodInfo (MethodInfo m)
{
if (VerboseOutput) {
PrintMethodBase (m);
Writer.WriteLine ("ReturnType={0}", m.ReturnType);
Writer.WriteLine ("ReturnTypeCustomAttributes={0}",
/* PrintEnumValue
(typeof(m.ReturnTypeCustomAttributes), m.ReturnTypeCustomAttributes) */
m.ReturnTypeCustomAttributes);
}
}
protected override void OnMethods (MethodsEventArgs e)
{
using (Indenter n1 = new Indenter (Writer)) {
Writer.WriteLine ("Methods:");
using (Indenter n2 = new Indenter (Writer)) {
foreach (MethodInfo m in e.Methods) {
Writer.WriteLine (m);
using (Indenter n3 = new Indenter
(Writer)) {
PrintMethodInfo (m);
}
}
}
}
}
}
public class TypeLoader {
// String collection
private ICollection assemblies = null;
private bool matchFullName = true;
private bool matchName = false;
private bool matchBase = false;
private bool matchMethodReturnType = false;
private bool matchNamespace = false;
public bool MatchFullName {
get {return matchFullName;}
set {matchFullName = value;}
}
public bool MatchClassName {
get {return matchName;}
set {matchName = value;}
}
public bool MatchBase {
get {return matchBase;}
set {matchBase = value;}
}
public bool MatchMethodReturnType {
get {return matchMethodReturnType;}
set {matchMethodReturnType = value;}
}
public bool MatchNamespace {
get {return matchNamespace;}
set {matchNamespace = value;}
}
public TypeLoader ()
{
}
public TypeLoader (ICollection assemblies)
{
this.assemblies = assemblies;
}
public ICollection Assemblies {
get {return assemblies;}
set {assemblies = value;}
}
public ICollection LoadTypes (string match)
{
if (assemblies == null)
throw new ArgumentNullException ("Assemblies");
IList found = new ArrayList ();
foreach (string a in assemblies) {
LoadMatchingTypesFrom (a, match, found);
}
return found;
}
private void LoadMatchingTypesFrom (string where, string match, IList
types)
{
Regex re = new Regex (match);
try {
Assembly a = Assembly.LoadFrom (where);
Type[] _types = a.GetTypes();
foreach (Type t in _types) {
if (Matches (re, t))
types.Add (t);
}
} catch (Exception e) {
Trace.WriteLine (String.Format (
"Unable to load type regex `{0}' from `{1}'.",
match, where));
Trace.WriteLine (e.ToString());
}
}
private bool Matches (Regex r, Type t)
{
bool f, c, b, rt, n;
f = c = b = rt = n = false;
if (MatchFullName)
f = r.Match(t.FullName).Success;
if (MatchClassName)
c = r.Match(t.Name).Success;
if (MatchNamespace)
n = r.Match(t.Namespace).Success;
if (MatchBase) {
b = (!MatchFullName ? false : r.Match
(t.BaseType.FullName).Success) ||
(!MatchClassName ? false : r.Match
(t.BaseType.Name).Success) ||
(!MatchNamespace ? false : r.Match
(t.BaseType.Namespace).Success);
}
// TODO: MatchMethodReturnType
Trace.WriteLine (String.Format("TypeLoader.Matches: c={0},
b={1}, rt={2}, n={3}", c, b, rt, n));
return f || c || b || rt || n;
}
}
internal class TextGrouper {
private int leftMargin = 0;
private int rightMargin = 80;
private int subsequentIndent = 0;
public int LeftMargin {
get {return leftMargin;}
set {leftMargin = value;}
}
public int RightMargin {
get {return rightMargin;}
set {rightMargin = value;}
}
public int SubsequentIndent {
get {return subsequentIndent;}
set {subsequentIndent = value;}
}
public TextGrouper ()
: this (0)
{
}
public TextGrouper (int leftMargin)
: this (leftMargin, 80)
{
}
public TextGrouper (int leftMargin, int rightMargin)
: this (leftMargin, rightMargin, 0)
{
}
public TextGrouper (int leftMargin, int rightMargin, int
subsequentIndent)
{
this.leftMargin = leftMargin;
this.rightMargin = rightMargin;
this.subsequentIndent = subsequentIndent;
}
private void WrapText (string text, int width, IList lines)
{
if (text.Length <= width) {
lines.Add (text);
return;
}
while (text.Length > width) {
int b = width;
if (!Char.IsWhiteSpace(text[b])) {
b = text.LastIndexOf (' ', b);
if (b == -1)
// couldn't find an earlier word break
b = width;
}
lines.Add (text.Substring (0, b));
text = text.Substring (b).Trim();
}
lines.Add (text);
}
private ICollection WrapText (string text, int width)
{
ArrayList lines = new ArrayList ();
string[] paragraphs = text.Split(new char[] {'\n'});
foreach (string p in paragraphs)
WrapText (p, width, lines);
return lines;
}
public string Group (string text)
{
// should be "- followingIndent", but need an extra space for
the '\n'.
int width = (RightMargin - LeftMargin) - (SubsequentIndent+1);
StringBuilder sb = new StringBuilder ();
string format1 = "{1}";
string formatN = "{0,-" + (LeftMargin + SubsequentIndent) +
"}{1}";
ICollection c = WrapText (text, width);
int last = c.Count;
string format = format1;
foreach (string s in c) {
string line = String.Format (format, "", s);
sb.Append (line);
if (--last != 0) {
format = formatN;
sb.Append ("\n");
}
}
return sb.ToString();
}
}
internal class OptionException : Exception {
public char ShortForm;
public OptionException (string reason, char shortForm )
: base (reason)
{
this.ShortForm = shortForm;
}
public OptionException (string reason)
: base (reason)
{
}
public OptionException (string reason, Exception inner)
: base (reason, inner)
{
}
}
internal class ProgramOptions {
private class Option {
public char ShortForm = '\0';
public string LongForm = null;
public string Description = null;
public bool Found = false;
public bool HasArgument = false;
public string ArgumentValue = null;
public string ArgumentDescription = null;
public Option (char shortForm, string longForm, string
description, string argDesc, bool hasArgument)
{
ShortForm = shortForm;
LongForm = longForm;
Description = description;
HasArgument = hasArgument;
ArgumentDescription = argDesc;
}
public Option (char shortForm, string description)
{
ShortForm = shortForm;
Description = description;
}
public Option (string longForm, string description)
{
LongForm = longForm;
Description = description;
}
}
// Option array
private ArrayList options = new ArrayList ();
// string array
private ArrayList unmatched = new ArrayList ();
public IList UnmatchedOptions {
get {return unmatched;}
}
public ProgramOptions ()
{
}
private void AddOption (Option opt)
{
options.Add (opt);
}
public void AddHelpOption ()
{
AddOption (new Option ('h', "help", "Display this help and
exit.", null, false));
}
public void AddOption (char shortForm, string description)
{
AddOption (new Option (shortForm, description));
}
public void AddArgumentOption (char shortForm, string description,
string argument)
{
AddOption (new Option (shortForm, null, description, argument,
true));
}
public void AddOption (string longForm, string description)
{
AddOption (new Option (longForm, description));
}
public void AddArgumentOption (string longForm, string description,
string argument)
{
AddOption (new Option ('\0', longForm, description, argument,
true));
}
public void AddOption (char shortForm, string longForm, string
description)
{
AddOption (new Option (shortForm, longForm, description, null,
false));
}
public void AddArgumentOption (char shortForm, string longForm, string
description, string argument)
{
AddOption (new Option (shortForm, longForm, description,
argument, true));
}
public virtual void ParseOptions (string[] options)
{
int len = options.Length;
bool handle = true;
for (int cur = 0; cur != len; ++cur) {
string option = options[cur];
// necessary?
if (option == null || option.Length == 0)
continue;
if (handle) {
if (option.StartsWith ("-")) {
// possible option
if (option == "--")
handle = false;
else if (option.StartsWith ("--"))
ParseLongOption (options, ref
cur);
else
ParseShortOptions (options,
ref cur);
}
else
unmatched.Add (option);
}
else
unmatched.Add (option);
}
}
private void ParseLongOption (string[] args, ref int currentIndex)
{
// get rid of "--"
string arg = args[currentIndex].Substring (2);
bool found = false;
foreach (Option o in options) {
if (o.LongForm == null)
continue;
if (!arg.StartsWith(o.LongForm))
continue;
found = true;
o.Found = true;
if (o.HasArgument) {
try {
o.ArgumentValue = arg.Substring
(arg.IndexOf('=')+1);
} catch (Exception e) {
throw new OptionException (
"missing argument to option
--" + o.LongForm,
e);
}
}
}
if (!found)
throw new OptionException (
String.Format ("Unrecognized option `{0}'",
args[currentIndex]));
}
private void ParseShortOptions (string[] args, ref int currentIndex)
{
string arg = args[currentIndex].Substring (1);
int needsArg = 0;
Option forArg = null;
for (int i = 0; i != arg.Length; ++i) {
bool found = false;
foreach (Option o in options) {
if (o.ShortForm != arg[i])
continue;
found = true;
o.Found = true;
if (o.HasArgument) {
++needsArg;
forArg = o;
}
}
if (!found)
throw new OptionException (
String.Format("Unrecognized option
`-{0}'", arg[i]));
}
if (needsArg > 1)
throw new OptionException ("too many options requiring
arguments specified");
else if (needsArg == 1) {
if (currentIndex == (args.Length - 1))
throw new OptionException ("missing argument
to option -" + forArg.ShortForm);
++currentIndex;
forArg.ArgumentValue = args[currentIndex];
}
}
public virtual void Clear ()
{
foreach (Option o in options) {
o.Found = false;
o.ArgumentValue = null;
}
}
private static readonly string[] OptionFormats =
{
// 0: no short, no long, no arg
"<invalid option format: 0>",
// 1: short only
" -{0}",
// 2: long only
" --{1}",
// 3: long & short
" -{0}, --{1}",
// 4: no short, no long, arg
"<invalid option format: 4>",
// 5: short w/ arg
" -{0} {2}",
// 6: long w/ arg
" --{1}={2}",
// 7: short & long w/ arg
" -{0}, --{1}={2}"
};
public virtual string OptionsHelp {
get {
StringBuilder sb = new StringBuilder ();
foreach (Option o in options) {
uint f_s = Convert.ToUInt32 (o.ShortForm !=
'\0');
uint f_l = Convert.ToUInt32 (o.LongForm !=
null);
uint f_h = Convert.ToUInt32 (o.HasArgument);
uint format = (f_s << 0) | (f_l << 1) | (f_h
<< 2);
string opt = String.Format
(OptionFormats[format],
o.ShortForm,
o.LongForm,
o.ArgumentDescription);
string fmt = null;
if (opt.Length < 30)
fmt = "{0,-30}{1}";
else
fmt = "{0,-30}\n{2,-30}{1}";
string d = new TextGrouper (30, 80, 2).Group
(o.Description);
sb.Append (String.Format (fmt, opt, d, ""));
sb.Append ("\n");
}
return sb.ToString ();
}
}
public static readonly string ProgramName =
Environment.GetCommandLineArgs()[0];
public bool FoundOption (char shortForm)
{
foreach (Option o in options) {
if (o.ShortForm != shortForm)
continue;
return o.Found;
}
return false;
}
public bool FoundOption (string longForm)
{
foreach (Option o in options) {
if (o.LongForm != longForm)
continue;
return o.Found;
}
return false;
}
public string FoundOptionValue (char shortForm)
{
foreach (Option o in options) {
if (o.ShortForm != shortForm)
continue;
return o.ArgumentValue;
}
return null;
}
public string FoundOptionValue (string longForm)
{
foreach (Option o in options) {
if (o.LongForm != longForm)
continue;
return o.ArgumentValue;
}
return null;
}
public bool FoundHelp {
get {return FoundOption ('h');}
}
}
internal class TypeIntrospectorOptions : ProgramOptions {
private static char onlyAssemblies = 'A';
private static char addAssemblies = 'a';
private static char matchAll = 'M';
private static char matchFullName = 'f';
private static char matchClass = 'C';
private static char matchBase = 'B';
private static char matchNamespace = 'N';
private static char matchReturnType = 'R';
private static char showBase = 'b';
private static char showConstructors = 'c';
private static char showEvents = 'e';
private static char showFields = 'f';
private static char showInterfaces = 'i';
private static char showMethods = 'm';
private static char showProperties = 'p';
private static char showTypeProperties = 't';
private static char showNonPublic = 'U';
private static char showMonoBroken = 'K';
private static char showAll = 'S';
private static char showInheritedMembers= 'r';
private static char verboseOutput = 'v';
private static char flattenHierarchy = 'F';
public TypeIntrospectorOptions ()
{
AddArgumentOption (onlyAssemblies, "only-assemblies",
"Only search for types within the specified " +
"assemblies. Assemblies are searched for " +
"within the directories specified with " +
"--only-directories.",
"<assembly-list>");
AddArgumentOption (addAssemblies, "add-assemblies",
"Add the specified assemblies to the list of " +
"assemblies searched for types.",
"<assembly-list>");
AddOption (matchAll, "match-all",
"Type names should be matched in all locations"
);
AddOption (matchFullName, "match-full-name",
"Match type names against the full type name " +
"(Namespace + Class Name).\n" +
"This is the default.");
AddOption (matchClass, "match-class",
"Match type names against only the class name");
AddOption (matchBase, "match-base",
"Match type names against the base class " +
"name.\nMatching of the base name is " +
"identical to top-level type matches--it " +
"matches the namespace, class name, or full " +
"type name.");
AddOption (matchNamespace, "match-namespace",
"Match the type's namespace.");
/*
AddOption (matchReturnType, "match-return-type",
"Match the return type of methods");
*/
AddOption (showBase, "show-base",
"Show the base class.");
AddOption (showConstructors, "show-constructors",
"Show the type's constructors.");
AddOption (showEvents, "show-events",
"Show the type's events.");
AddOption (showFields, "show-fields",
"Show the type's fields.");
AddOption (showInterfaces, "show-interfaces",
"Show the type's interfaces");
AddOption (showMethods, "show-methods",
"Show the type's methods.");
AddOption (showProperties, "show-properties",
"Show the type's properties.");
AddOption (showTypeProperties, "show-type-properties",
"Show the properties of the type's System.Type"+
"object.\nThis is not set by -S.");
AddOption (showInheritedMembers, "show-inherited-members",
"Show inherited members (members declared by " +
"base classes).\nThis is not set by -S.");
AddOption (showNonPublic, "show-non-public",
"Show non-public members.\n" +
"This is not set by -S.");
AddOption (showMonoBroken, "show-mono-broken",
"Some attributes shown in verbose output " +
"cause exceptions when run under Mono. " +
"These attributes are not shown by default. "+
"This option shows these disabled attributes."+
"\nThis is not set by -S.");
AddOption (showAll, "show-all",
"Show everything except System.Type "+
"properties, inherited members, non-public "+
"members, and \"broken\" Mono attributes.");
AddOption (verboseOutput, "verbose-output",
"Print the contents of all the public " +
"attributes of the reflection information " +
"classes.");
AddOption (flattenHierarchy, "flatten-hierarchy",
"Static members of base types should be " +
"displayed.");
AddHelpOption ();
}
public override void ParseOptions (string[] options)
{
base.ParseOptions (options);
_showAll = base.FoundOption (showAll);
_matchAll = base.FoundOption (matchAll);
}
public IList Types {
get {return base.UnmatchedOptions;}
}
private bool _matchAll;
public bool MatchAll {
get {return _matchAll;}
}
// default: true;
public bool MatchFullName {
get {
if (!MatchClassName && !MatchNamespace && !MatchBase
&&
!MatchReturnType)
return true;
return MatchAll || base.FoundOption (matchFullName);
}
}
public bool MatchClassName {
get {
return MatchAll || base.FoundOption (matchClass);
}
}
public bool MatchNamespace {
get {
return MatchAll || base.FoundOption (matchNamespace);
}
}
public bool MatchBase {
get {
return MatchAll || base.FoundOption (matchBase);
}
}
public bool MatchReturnType {
get {
return MatchAll || base.FoundOption (matchReturnType);
}
}
private bool _showAll;
public bool ShowAll {
get {
return _showAll;
}
}
public bool ShowBase {
get {
return ShowAll || base.FoundOption (showBase);
}
}
public bool ShowConstructors {
get {
return ShowAll || base.FoundOption (showConstructors);
}
}
public bool ShowEvents {
get {
return ShowAll || base.FoundOption (showEvents);
}
}
public bool ShowFields {
get {
return ShowAll || base.FoundOption (showFields);
}
}
public bool ShowInterfaces {
get {
return ShowAll || base.FoundOption (showInterfaces);
}
}
public bool ShowMethods {
get {
return ShowAll || base.FoundOption (showMethods);
}
}
public bool ShowProperties {
get {
return ShowAll || base.FoundOption (showProperties);
}
}
public bool ShowTypeProperties {
get {
return base.FoundOption (showTypeProperties);
}
}
public bool ShowInheritedMembers {
get {
return base.FoundOption (showInheritedMembers);
}
}
public bool ShowNonPublic {
get {
return base.FoundOption (showNonPublic);
}
}
public bool ShowMonoBroken {
get {
return base.FoundOption (showMonoBroken);
}
}
public bool FlattenHierarchy {
get {
return base.FoundOption (flattenHierarchy);
}
}
public bool VerboseOutput {
get {
return base.FoundOption (verboseOutput);
}
}
private static string[] GetDefaultAssemblies ()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies
();
string sysdir = null;
foreach (Assembly a in assemblies) {
string codebase = a.CodeBase;
if (codebase.EndsWith ("corlib.dll")) {
sysdir = codebase.Substring (0,
codebase.LastIndexOf ("/"));
break;
}
}
return Directory.GetFiles (new Uri (sysdir).LocalPath,
"*.dll");
}
public ICollection Assemblies {
get {
string o = base.FoundOptionValue (onlyAssemblies);
string a = base.FoundOptionValue (addAssemblies);
ArrayList r = new ArrayList ();
if (o == null) {
r.AddRange (GetDefaultAssemblies ());
}
else {
r.AddRange (o.Split (Path.PathSeparator));
}
if (a != null)
r.AddRange (a.Split (Path.PathSeparator));
return r;
}
}
public override string OptionsHelp {
get {
StringBuilder sb = new StringBuilder ();
TextGrouper tg0 = new TextGrouper ();
TextGrouper tg4 = new TextGrouper (4, 80, 0);
sb.Append (
"Prints out type information\n" +
"\n" +
"Usage: " + ProgramName + " [options]
<types>\n" +
"\n" +
"Where [options] can include:\n");
sb.Append (base.OptionsHelp);
sb.Append (
"\n" +
tg0.Group (
"<assembly-list> is a `" +
Path.PathSeparator + "'-delimited list. " +
"For example, `" +
String.Format ("foo{0}bar{0}baz",
Path.PathSeparator) + "' is a
valid list.\n") +
"\n" +
tg0.Group (
"<types> is interpreted as a regular
expression. As regular expression " +
"meta-characters are seldom used in
class names, specifying a type name " +
"looks for all types that have the
specified type name as a substring.") +
"\n\n"
);
sb.Append ("The default assemblies are:\n");
foreach (string s in GetDefaultAssemblies ()) {
sb.Append (String.Format (" {0}\n", s));
}
sb.Append ("\n");
sb.Append (String.Format (
"Examples:\n" +
" {0} Type\n", ProgramName));
sb.Append (String.Format (" {0}", tg4.Group ("Finds
all types that have `Type' (case-sensitive) as part of their name.")));
sb.Append (String.Format (
"\n\n" +
" {0} [Tt][Yy][Pp][Ee]\n",
ProgramName));
sb.Append (String.Format (" {0}", tg4.Group ("Finds
all types that have `Type' (case-insensitive) as part of their name.")));
sb.Append (String.Format (
"\n\n" +
" {0} -A my-assembly.dll MyType\n",
ProgramName));
sb.Append (String.Format (" {0}", tg4.Group ("Finds
all types that have `MyType' as part of their name within the assembly
`my-assembly'.")));
sb.Append (String.Format (
"\n\n" +
" {0} -SKt MyType\n", ProgramName));
sb.Append (String.Format (" {0}", tg4.Group ("Find
all types that have `MyType' as part of their name, and for those types show all
information (-S) including information Mono generates exceptions for (-K) and show the
values of the public attributes of the System.Type object for the type.")));
return sb.ToString ();
}
}
}
public class ConsoleOutput {
private static void TraceStringArray (string message, IEnumerable
contents)
{
Trace.WriteLine (message);
foreach (string s in contents) {
Trace.WriteLine (" " + s);
}
}
public static void Main (string[] args)
{
TypeIntrospectorOptions options = new TypeIntrospectorOptions
();
try {
options.ParseOptions (args);
} catch (Exception e) {
Console.WriteLine (e.Message);
Console.WriteLine ("See `{0} --help' for more
information", ProgramOptions.ProgramName);
// Console.WriteLine ("** Full Message continues:\n" +
e);
return;
}
if (options.FoundHelp) {
Console.WriteLine (options.OptionsHelp);
return;
}
if (options.Types.Count == 0) {
Console.WriteLine ("No types specified.");
Console.WriteLine ("See `{0} --help' for more
information", ProgramOptions.ProgramName);
return;
}
TraceStringArray ("Search Assemblies: ", options.Assemblies);
TraceStringArray ("Search for Types: ", options.Types);
TypeLoader loader = new TypeLoader (options.Assemblies);
loader.MatchBase = options.MatchBase;
loader.MatchFullName = options.MatchFullName;
loader.MatchClassName = options.MatchClassName;
loader.MatchNamespace = options.MatchNamespace;
loader.MatchMethodReturnType = options.MatchReturnType;
TypeDisplayer p = new VerboseTreeTypeDisplayer (Console.Out);
p.VerboseOutput = options.VerboseOutput;
p.ShowBase = options.ShowBase;
p.ShowConstructors = options.ShowConstructors;
p.ShowEvents = options.ShowEvents;
p.ShowFields = options.ShowFields;
p.ShowInterfaces = options.ShowInterfaces;
p.ShowMethods = options.ShowMethods;
p.ShowProperties = options.ShowProperties;
p.ShowTypeProperties = options.ShowTypeProperties;
p.ShowInheritedMembers = options.ShowInheritedMembers;
p.ShowNonPublic = options.ShowNonPublic;
p.ShowMonoBroken = options.ShowMonoBroken;
p.FlattenHierarchy = options.FlattenHierarchy;
foreach (string t in options.Types) {
try {
ICollection typesFound = loader.LoadTypes (t);
if (typesFound.Count > 0)
foreach (Type type in
loader.LoadTypes(t))
p.Parse (type);
else
Console.WriteLine ("Unable to find
type `{0}'.", t);
} catch (Exception e) {
Console.WriteLine ("Unable to parse type
`{0}': {1}.", t, e.ToString());
}
}
}
}
}