从StackFrame获取Type T.

Ern*_*ieL 3 .net c# generics reflection

目标是基于调用my方法的类型创建一个通用实例.

问题是,当从泛型调用时,StackFrame似乎只包含开放定义类型参数而不是封闭定义类型参数.如何从StackFrame中获取类型参数?与此问题类似.我想我的情况有所不同,因为Log.Debug是从一个封闭的方法调用的.

如果StackFrame不是正确的方法,除IoC以外的任何建议?此代码用于填写对我的Unity容器的引用不可用的情况.

using System;
using System.Reflection;

namespace ReflectionTest
{
    public class Logger
    {
        private readonly string loggerName;
        protected Logger(string loggerName) { this.loggerName = loggerName; }
        public void Debug(string message) { Console.WriteLine(string.Format("{0} - {1}", loggerName, message)); }
    }

    public class Logger<T> : Logger
    {
        public Logger() : base(typeof(T).FullName) { }
    }

    public static class Log
    {
        public static void Debug(string message)
        {
            // Determine the calling function, and create a Logger<T> for it.
            System.Diagnostics.StackFrame frame = new System.Diagnostics.StackFrame(1);
            MethodBase method = frame.GetMethod();

            /// When method is from a generic class, 
            /// the method.ReflectedType definintion is open: Type.ContainsGenericParameters is true
            /// How do I get the generic parameters of method.ReflectedType so 
            /// Activator.CreateInstance() will not throw?
            Type logType = typeof(Logger<>);
            Type constructed = logType.MakeGenericType(new Type[] { method.ReflectedType });

            Logger logger = (Logger)Activator.CreateInstance(constructed);

            logger.Debug(message);
        }
    }

    public class MyBase<T>
    {
        public void Run()
        {
            Log.Debug("Run Generic");   // throws on Activator.CreateInstance()
        }
    }

    class Program
    {
        static void Works()
        {
            Log.Debug("Run NonGeneric");    // works
        }

        static void DoesNotWork()
        {
            MyBase<int> b = new MyBase<int>();
            b.Run();
        }

        static void Main(string[] args)
        {
            Works();
            DoesNotWork();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 17

堆栈帧不可靠,仅用于调试目的.你不能假设有任何有用的东西.这就是它在"诊断"命名空间中的原因.

但更一般地说,您的问题表明了对堆栈框架告诉您的内容存在根本性的误解.你说

目标是基于调用my方法的类型创建一个通用实例.

堆栈框架实际上并没有告诉您谁调用了您的方法.堆栈框架告诉您控件将返回的位置.堆栈框架是延续的具体化.这个事实谁调用的方法,并在那里控制将返回到几乎总是同样的事情,是你的问题的根源,但我向你保证,他们需要是不一样的.

特别是,目前预览版中即将出现的"异步/等待"功能证明了这一点.从await恢复的代码在堆栈框架上没有关于谁最初调用它的线索; 这些信息永远消失了.由于下一个要运行的代码在逻辑上与最初调用该方法的代码分离,因此堆栈帧不包含该信息.

我们不需要像这样充满异国情调.例如,假设方法M包含对方法N的调用,并且N调用方法O.如果抖动选择在M中内联N,则从O观察到的堆栈帧将不包含N.堆栈帧告诉您控制在何处当前方法返回时恢复.当O返回时,控制将在M内恢复,而不是N,因此堆栈帧不包含关于N的任何信息.

  • 实际上,System.Diagnostics中有很多东西**很有用,比如Process类(例如Process.Start).因此命名空间不会传达不可靠性.您只需要了解内联等使堆栈框架不可靠的内容. (6认同)