这是我在stackoverflow中的第一个问题,我是使用反射的初学者。
我想转储对象实例的所有值以供参考(以跟踪测试中使用的值)。我使用Compact Framework 3.5而不是完整的框架。请记住这些建议。
想象一下以下课程:
public class Camera : IDisposable
{
public Camera.FilenameProperties SnapshotFile;
public double DigitalZoomFactor { get; set; }
public bool DisplayHistogram { get; set; }
public int ImageUpdateInterval { get; set; }
public Camera.ImprintCaptionPosType ImprintCaptionPos { get; set; }
public string ImprintCaptionString { get; set; }
}
其中'特殊'类型是:
public class FilenameProperties
{
public string Directory { get; set; }
public string Filename { get; set; }
public Camera.FilenamePaddingType FilenamePadding { get; set; }
public Camera.ImageType ImageFormatType { get; set; }
public Camera.ImageResolutionType ImageResolution { get; set; }
public int JPGQuality { get; set; }
public void Restore();
public void Save();
public enum Fnametype
{
tSnapshot = 0,
tCircularCapture = 1,
}
}
public enum ImprintCaptionPosType
{
Disabled = 0,
LowerRight = 1,
LowerLeft = 2,
LowerCenter = 3,
UpperRight = 4,
UpperLeft = 5,
UpperCenter = 6,
Center = 7,
}
现在,我可以获取“基本”名称和属性以及相机实例的字段名称:
Camera cam = new Camera();
dumpProperties(cam);
...
void dumpProperties(object oClass)
{
System.Diagnostics.Debug.WriteLine(oClass.ToString());
FieldInfo[] _Info = oClass.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
for(int i = 0; i<_Info.Length; i++)
{
System.Diagnostics.Debug.WriteLine(_Info[i].Name + ":'" + _Info[i].GetValue(oClass).ToString()+"'");
}
foreach (PropertyInfo pi in oClass.GetType().GetProperties())
{
System.Diagnostics.Debug.WriteLine(pi.Name + ":'" + pi.GetValue(oClass, null)
+ "' Type=" + pi.PropertyType.ToString());
}
}
然后得到这样的东西:
Intermec.Multimedia.Camera
SnapshotFile:'Intermec.Multimedia.Camera+FilenameProperties'
DigitalZoomFactor:'1' Type=System.Double
DisplayHistogram:'False' Type=System.Boolean
ImageUpdateInterval:'1' Type=System.Int32
ImprintCaptionPos:'Disabled' Type=Intermec.Multimedia.Camera+ImprintCaptionPosType
ImprintCaptionString:'' Type=System.String
现在,对于像DigitalZoomFactor和ImageUpdateInterval这样的简单属性,我得到了我需要的东西,但是对于嵌套类(正确的措辞?)我只得到了类型,例如SnapshotFile。对于嵌套枚举,我得到的值与'ImprintCaptionPos'相同。
如何获取SnapshotFile字段/属性的FilenameProperties.Filename等嵌套值的值?
如果我使用dumpProperties(cam.SnapshotFile),我会得到我想要的输出:
Intermec.Multimedia.Camera+FilenameProperties
Directory:'\Program Files\FrmCamera' Type=System.String
Filename:'myphoto' Type=System.String
ImageFormatType:'JPG' Type=Intermec.Multimedia.Camera+ImageType
FilenamePadding:'None' Type=Intermec.Multimedia.Camera+FilenamePaddingType
ImageResolution:'Medium' Type=Intermec.Multimedia.Camera+ImageResolutionType
JPGQuality:'100' Type=System.Int32
但我怎样才能实现自动化呢?
我做了很多搜索和测试编码,但无法找到解决方案。问题似乎是让字段的实例能够通过它进行迭代。
我没有Camera类的源代码,因此无法在其中添加或删除代码。
有人可以帮忙吗?
我需要得到调试器显示的内容:
答案 0 :(得分:1)
您只需使用递归,如果您的属性是类,则循环回该方法。这是我们使用的XML序列化例程的示例,它使用反射有效地遍历目标的属性,并从中生成XElement
。你的逻辑会有所不同,因为你不打算构建XML,但你要做的事情的结构将非常相似。
public XElement Serialize(object source,
string objectName,
bool includeNonPublicProperties)
{
XElement element;
var flags = BindingFlags.Instance | BindingFlags.Public;
if(includeNonPublicProperties)
{
flags |= BindingFlags.NonPublic;
}
var props = source.GetType().GetProperties(flags);
var type = source.GetType();
string nodeName;
if(objectName == null)
{
if (type.IsGenericType)
{
nodeName = type.Name.CropAtLast('`');
}
else
{
nodeName = type.Name;
}
}
else
{
nodeName = objectName;
}
element = new XElement(nodeName);
foreach (var prop in props)
{
string name = prop.Name;
string value = null;
bool valIsElement = false;
if (!prop.CanRead) continue;
if(prop.PropertyType.IsEnum)
{
value = prop.GetValue(source, null).ToString();
}
else
{
string typeName;
if (prop.PropertyType.IsNullable())
{
typeName = prop.PropertyType.GetGenericArguments()[0].Name;
}
else
{
typeName = prop.PropertyType.Name;
}
switch (typeName)
{
case "String":
case "Boolean":
case "Byte":
case "TimeSpan":
case "Single":
case "Double":
case "Int16":
case "UInt16":
case "Int32":
case "UInt32":
case "Int64":
case "UInt64":
value = (prop.GetValue(source, null) ?? string.Empty).ToString();
break;
case "DateTime":
try
{
var tempDT = Convert.ToDateTime(prop.GetValue(source, null));
if (tempDT == DateTime.MinValue) continue;
value = tempDT.ToString("MM/dd/yyyy HH:mm:ss.fffffff");
}
catch(Exception ex)
{
continue;
}
break;
default:
var o = prop.GetValue(source, null);
XElement child;
if (o == null)
{
child = new XElement(prop.Name);
}
else
{
child = Serialize(o, prop.Name, includeNonPublicProperties);
}
element.Add(child);
valIsElement = true;
break;
}
}
if (!valIsElement)
{
element.AddAttribute(name, value);
}
}
return element;
}
答案 1 :(得分:1)
好的,我找到了一种方法(一种解决方法)来使用here中的代码获取所有属性(在XML中,但是谁在乎):
输出是xml,但对我来说是可以接受的。这里有一段摘录:
<xml version="1.0" encoding="utf-8">
<Camera xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...
<ImprintCaptionPos>Disabled</ImprintCaptionPos>
<SnapshotFile>
<Directory>\\Program Files\\FrmCamera</Directory>
<Filename>myphoto</Filename>
<ImageFormatType>JPG</ImageFormatType>
<FilenamePadding>None</FilenamePadding>
<ImageResolution>Medium</ImageResolution>
<JPGQuality>100</JPGQuality>
</SnapshotFile>
...
在我的代码中,我只需要调用
string s = serialization.mySerialize.SerializeObject<Intermec.Multimedia.Camera>(cam);
获取实例的所有当前属性的“转储”。
感谢大家的帮助。可能我被我的问题误解了,反思无法给出我想要的东西。
由于
约瑟夫
答案 2 :(得分:0)
您必须像对外层类一样对所有内部对象成员进行迭代。对于完整的.NET类型集实现它将是一个练习。下面是简单实现的伪代码
void dumpProperties(object target)
{
if (target.GetType().IsSimple() || target.GetType().IsMethodImplemented("ToString"))
System.Diagnostics.Debug.WriteLine(target.ToString());
else if (target is IEnumerable)
{
foreach (object item in (IEnumerable)target)
{
System.Diagnostics.Debug.WriteLine(dumpProperties(target));
}
}
else
{
foreach (FieldInfo fieldInfo in target.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance))
{
System.Diagnostics.Debug.WriteLine(dumpProperties(fieldInfo.FieldHandle.Value));
}
foreach (PropertyInfo propertyInfo in oClass.GetType().GetProperties())
{
System.Diagnostics.Debug.WriteLine(dumpProperties(propertyInfo.GetGetMethod().MethodHandle.Value));
}
}
}
或者您可以使用Cinchoo framework,它具有内置函数来转储任何对象。
Console.WriteLine(ChoObject.ToString(camera));