C# 使用反射访问嵌套结构的成员

发布于 2025-01-11 05:44:14 字数 5301 浏览 0 评论 0原文

我正在使用 C# 反射来实现允许用户访问内部程序变量的脚本语言。

它适用于简单的构造,但是当我尝试访问实例化结构中的数据时,它总是给出 0 作为数据值。 我的测试程序:

using System;
using System.Reflection;

namespace ConsoleApp5
{
    public class TST         // Test class
    {
        public struct S1_t
        {
            public UInt32 one;
            public UInt32 two;
        }
        public S1_t t1 = new S1_t();
        public UInt32 x;
        public TST()
        {
            t1.one = 6977;
            t1.two = 2;
            x = 7769;
        }
    }

    public class NFC
    {
        public TST tst = new TST();
    }

    public class PRD
    {
        public NFC nfc = new NFC();
    }

    class Program
    {

        private static bool GetFullVarString(Type root, string[] varNamePath, out string valStr, int index = 0)
        {
            Object targetObj;
            bool status = false;
            if (index >= varNamePath.Length)    // Guard
            {
                valStr = "";
                return false;
            }

            targetObj = Activator.CreateInstance(root);
            
            string varValStr = "";
            try
            {
                foreach (MemberInfo member in root.GetMembers())    // BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic))
                {
                    if (member.Name != varNamePath[index])
                        continue;

                    /* Have we found the variable we're looking for?    */
                    if (member.MemberType == MemberTypes.Field)
                    {
                        FieldInfo fieldInfo = ((FieldInfo)member);
                        if (fieldInfo.GetValue(targetObj) != null)
                        {
                            var miVal = fieldInfo.GetValue(targetObj);
                            Console.WriteLine(String.Format(" Field Type: {0}", fieldInfo.FieldType.ToString()));
                            Type thisType = Type.GetType(fieldInfo.FieldType.FullName.ToString());
                            Boolean isStruct = thisType.IsValueType && !thisType.IsEnum && 
                                !(fieldInfo.FieldType.ToString().StartsWith("System"));
                            Console.WriteLine(String.Format(" IsStruct: {0}", isStruct.ToString()));

                            if (fieldInfo.FieldType.IsClass)
                            {
                                /* We've found a child class, so we need to change
                                 * the root type and step into it.
                                 */
                                Type newType = Type.GetType(fieldInfo.FieldType.FullName.ToString());
                                status = GetFullVarString(newType, varNamePath, out varValStr, index + 1);
                            }

                            else if (isStruct)
                            {
                                /* We've found a child struct, so we need to change
                                 * the root type and step into it.
                                 */
                                Type newType = Type.GetType(fieldInfo.FieldType.FullName.ToString());
                                status = GetFullVarString(newType, varNamePath, out varValStr, index + 1);
                            }
                            else
                            {
                                varValStr = miVal.ToString();
                            }
                            status = true;
                            break;
                        }
                    }
                    else if (member.MemberType == MemberTypes.NestedType)
                    {
                        Type nestedType = (Type)member;     // MemberInfo that is a NestedType is just a Type itself
                        status = GetFullVarString(nestedType, varNamePath, out varValStr, index + 1);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(String.Format("Exception: {0}", ex.Message));
                status = false;
            }

            valStr = varValStr;
            return status;
        }

        static void Main(string[] args)
        {
            PRD prd = new PRD();
            string fullVar, tstr;

            Type root = typeof(PRD);

            fullVar = "nfc.tst.x";
            GetFullVarString(root, fullVar.Split('.'), out tstr);
            Console.WriteLine(String.Format("{0} = {1}", fullVar, tstr));

            fullVar = "nfc.tst.t1.one";
            GetFullVarString(root, fullVar.Split('.'), out tstr);
            Console.WriteLine(String.Format("{0} = {1}", fullVar, tstr));

            Console.ReadKey();
        }
    }
}

输出显示 TST 类底部的变量“x”显示正常,但 t1 结构的成员则不然。

 Field Type: ConsoleApp5.NFC
 IsStruct: False
 Field Type: ConsoleApp5.TST
 IsStruct: False
 Field Type: System.UInt32
 IsStruct: False
nfc.tst.x = 7769
 Field Type: ConsoleApp5.NFC
 IsStruct: False
 Field Type: ConsoleApp5.TST
 IsStruct: False
 Field Type: ConsoleApp5.TST+S1_t
 IsStruct: True
 Field Type: System.UInt32
 IsStruct: False
nfc.tst.t1.one = 0

我想这可能与在非类结构上使用 Activator 类有关,但我不知道。

有什么帮助吗?

I am using C# reflection to implement a scripting language that allows the user to have access to internal program variables.

It works for simple constructs, but when I try to access data in instantiated structures, it always gives 0 as the data value.
My test program:

using System;
using System.Reflection;

namespace ConsoleApp5
{
    public class TST         // Test class
    {
        public struct S1_t
        {
            public UInt32 one;
            public UInt32 two;
        }
        public S1_t t1 = new S1_t();
        public UInt32 x;
        public TST()
        {
            t1.one = 6977;
            t1.two = 2;
            x = 7769;
        }
    }

    public class NFC
    {
        public TST tst = new TST();
    }

    public class PRD
    {
        public NFC nfc = new NFC();
    }

    class Program
    {

        private static bool GetFullVarString(Type root, string[] varNamePath, out string valStr, int index = 0)
        {
            Object targetObj;
            bool status = false;
            if (index >= varNamePath.Length)    // Guard
            {
                valStr = "";
                return false;
            }

            targetObj = Activator.CreateInstance(root);
            
            string varValStr = "";
            try
            {
                foreach (MemberInfo member in root.GetMembers())    // BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic))
                {
                    if (member.Name != varNamePath[index])
                        continue;

                    /* Have we found the variable we're looking for?    */
                    if (member.MemberType == MemberTypes.Field)
                    {
                        FieldInfo fieldInfo = ((FieldInfo)member);
                        if (fieldInfo.GetValue(targetObj) != null)
                        {
                            var miVal = fieldInfo.GetValue(targetObj);
                            Console.WriteLine(String.Format(" Field Type: {0}", fieldInfo.FieldType.ToString()));
                            Type thisType = Type.GetType(fieldInfo.FieldType.FullName.ToString());
                            Boolean isStruct = thisType.IsValueType && !thisType.IsEnum && 
                                !(fieldInfo.FieldType.ToString().StartsWith("System"));
                            Console.WriteLine(String.Format(" IsStruct: {0}", isStruct.ToString()));

                            if (fieldInfo.FieldType.IsClass)
                            {
                                /* We've found a child class, so we need to change
                                 * the root type and step into it.
                                 */
                                Type newType = Type.GetType(fieldInfo.FieldType.FullName.ToString());
                                status = GetFullVarString(newType, varNamePath, out varValStr, index + 1);
                            }

                            else if (isStruct)
                            {
                                /* We've found a child struct, so we need to change
                                 * the root type and step into it.
                                 */
                                Type newType = Type.GetType(fieldInfo.FieldType.FullName.ToString());
                                status = GetFullVarString(newType, varNamePath, out varValStr, index + 1);
                            }
                            else
                            {
                                varValStr = miVal.ToString();
                            }
                            status = true;
                            break;
                        }
                    }
                    else if (member.MemberType == MemberTypes.NestedType)
                    {
                        Type nestedType = (Type)member;     // MemberInfo that is a NestedType is just a Type itself
                        status = GetFullVarString(nestedType, varNamePath, out varValStr, index + 1);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(String.Format("Exception: {0}", ex.Message));
                status = false;
            }

            valStr = varValStr;
            return status;
        }

        static void Main(string[] args)
        {
            PRD prd = new PRD();
            string fullVar, tstr;

            Type root = typeof(PRD);

            fullVar = "nfc.tst.x";
            GetFullVarString(root, fullVar.Split('.'), out tstr);
            Console.WriteLine(String.Format("{0} = {1}", fullVar, tstr));

            fullVar = "nfc.tst.t1.one";
            GetFullVarString(root, fullVar.Split('.'), out tstr);
            Console.WriteLine(String.Format("{0} = {1}", fullVar, tstr));

            Console.ReadKey();
        }
    }
}

The output shows that the variable 'x' at the base of the TST class displays fine, but the member of the t1 structure does not.

 Field Type: ConsoleApp5.NFC
 IsStruct: False
 Field Type: ConsoleApp5.TST
 IsStruct: False
 Field Type: System.UInt32
 IsStruct: False
nfc.tst.x = 7769
 Field Type: ConsoleApp5.NFC
 IsStruct: False
 Field Type: ConsoleApp5.TST
 IsStruct: False
 Field Type: ConsoleApp5.TST+S1_t
 IsStruct: True
 Field Type: System.UInt32
 IsStruct: False
nfc.tst.t1.one = 0

I'm thinking that maybe it has to do with using the Activator class on the non-class structure, but I have no idea.

Any help??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文