3

これはスタックオーバーフローでの最初の質問であり、リフレクションの使用の初心者です。

オブジェクト インスタンスのすべての値を参照用にダンプしたいと考えています (テストで使用された値を追跡するため)。完全なフレームワークではなく、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 クラスのソース コードがないため、そこにコードを追加または削除することはできません。

誰でも助けることができますか?

デバッガーが示すようなものを取得する必要があります。 ここに画像の説明を入力

4

3 に答える 3

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;
}
于 2012-11-14T14:19:13.257 に答える
1

OK、ここからのコードを使用してすべてのプロパティを取得する方法 (回避策) を見つけます (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);

インスタンスの現在のすべてのプロパティの「ダンプ」を取得します。

ご協力いただきありがとうございます。おそらく私は私の質問を誤解しており、反省は私が望むものを与えることができません.

ありがとう

ヨーゼフ

于 2012-11-15T14:47:20.847 に答える
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 フレームワークを使用できます。

Console.WriteLine(ChoObject.ToString(camera));
于 2012-11-14T13:29:55.507 に答える