Linq in Action (거침없이 배우는 LINQ)라는 책에 보면 ObjectDumper를 사용하는 부분이 많이 등장한다.
닷넷의 어떤 객체에 대해 출력을 쉽게하기 위해 만든 유틸리티 클래스인 것 같다.
구현은 리플렉션을 통해 하지 않았을까 추측해본다.
사이트: http://objectdumper.codeplex.com
메뉴탭에서 DOWNLOADS를 눌러도 릴리즈를 가지고 있지 않다(This project has no releases.)라는 메시지가 보인다.
크냥 소스코드를 받아서 빌드했다. ReleaseBinaries 모드의 결과 => ObjectDumper.dll
잘 돌아가나 해서 혹시 테스트를 해보았는데,,, 아래와 비슷하게 만들면 된다.
using ObjectDumper;
var c = new Class1();
textBox1.Text = c.Something();
var r = c.DumpToString("test");
MessageBox.Show(r);
Linq in Action에서는 ObjectDumber.Write(object) 식으로 사용을 했는데, ObjectDumber는 네임스페이스로 바뀌고 정적메소드 Dumper가 추가되었다. TextWriter를 사용할 수 있다면 아래처럼 사용하면 될 것이다. (개인적으로 제네릭 버전의 확장 메소드가 좋은 것 같다.)
콘솔 애플리케이션에서는 Dump메소드에 3번째 인자에 Console.Out을 지정하면 콘솔에 바로 출력을 할 수 있다.
using System;
using ObjectDumper;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var w = new WhatTheClass();
w.The = "Class";
Dumper.Dump(w, "WhatTheClass", Console.Out);
}
}
class WhatTheClass
{
public string The {get;set;}
public string What()
{
return The;
}
}
}
결과
참고로 구현은 InternalDump라는 정적메소드에서 동작을 한다.
System.Reflection을 이용하고, InternalDump를 재귀호출을 하게끔 구현되어 있었다.
private static void InternalDump(int indentationLevel, string name, object value, TextWriter writer, ObjectIDGenerator idGenerator, bool recursiveDump)
{
var indentation = new string(' ', indentationLevel * 3);
if (value == null)
{
writer.WriteLine("{0}{1} = <null>", indentation, name);
return;
}
Type type = value.GetType();
// figure out if this is an object that has already been dumped, or is currently being dumped
string keyRef = string.Empty;
string keyPrefix = string.Empty;
if (!type.IsValueType)
{
bool firstTime;
long key = idGenerator.GetId(value, out firstTime);
if (!firstTime)
keyRef = string.Format(CultureInfo.InvariantCulture, " (see #{0})", key);
else
{
keyPrefix = string.Format(CultureInfo.InvariantCulture, "#{0}: ", key);
}
}
// work out how a simple dump of the value should be done
bool isString = value is string;
string typeName = value.GetType().FullName;
string formattedValue = value.ToString();
var exception = value as Exception;
if (exception != null)
{
formattedValue = exception.GetType().Name + ": " + exception.Message;
}
if (formattedValue == typeName)
formattedValue = string.Empty;
else
{
// escape tabs and line feeds
formattedValue = formattedValue.Replace("\t", "\\t").Replace("\n", "\\n").Replace("\r", "\\r");
// chop at 80 characters
int length = formattedValue.Length;
if (length > 80)
formattedValue = formattedValue.Substring(0, 80);
if (isString)
formattedValue = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", formattedValue);
if (length > 80)
formattedValue += " (+" + (length - 80) + " chars)";
formattedValue = " = " + formattedValue;
}
writer.WriteLine("{0}{1}{2}{3} [{4}]{5}", indentation, keyPrefix, name, formattedValue, value.GetType(), keyRef);
// Avoid dumping objects we've already dumped, or is already in the process of dumping
if (keyRef.Length > 0)
return;
// don't dump strings, we already got at around 80 characters of those dumped
if (isString)
return;
// don't dump value-types in the System namespace
if (type.IsValueType && type.FullName == "System." + type.Name)
return;
// Avoid certain types that will result in endless recursion
if (type.FullName == "System.Reflection." + type.Name)
return;
if (value is System.Security.Principal.SecurityIdentifier)
return;
if (!recursiveDump)
return;
PropertyInfo[] properties =
(from property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
where property.GetIndexParameters().Length == 0
&& property.CanRead
select property).ToArray();
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToArray();
if (properties.Length == 0 && fields.Length == 0)
return;
writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}{{", indentation));
if (properties.Length > 0)
{
writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} properties {{", indentation));
foreach (PropertyInfo pi in properties)
{
try
{
object propertyValue = pi.GetValue(value, null);
InternalDump(indentationLevel + 2, pi.Name, propertyValue, writer, idGenerator, true);
}
catch (TargetInvocationException ex)
{
InternalDump(indentationLevel + 2, pi.Name, ex, writer, idGenerator, false);
}
catch (ArgumentException ex)
{
InternalDump(indentationLevel + 2, pi.Name, ex, writer, idGenerator, false);
}
catch (RemotingException ex)
{
InternalDump(indentationLevel + 2, pi.Name, ex, writer, idGenerator, false);
}
}
writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} }}", indentation));
}
if (fields.Length > 0)
{
writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} fields {{", indentation));
foreach (FieldInfo field in fields)
{
try
{
object fieldValue = field.GetValue(value);
InternalDump(indentationLevel + 2, field.Name, fieldValue, writer, idGenerator, true);
}
catch (TargetInvocationException ex)
{
InternalDump(indentationLevel + 2, field.Name, ex, writer, idGenerator, false);
}
}
writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} }}", indentation));
}
writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}}}", indentation));
}
'Programing > 닷넷' 카테고리의 다른 글
윈폼::ESC를 눌러 닫기 (0) | 2013.01.11 |
---|---|
애플리케이션 설정(app.config) (0) | 2013.01.10 |
Microsoft Chart Controls (차트컨트롤) (0) | 2013.01.10 |
윈폼 다국어(i18n) 개발하기 - Best Practice (1) | 2013.01.09 |
C#프로그래밍가이드 - 주석 (0) | 2013.01.08 |