【问题标题】:How to know when any method is called in my application code?如何知道我的应用程序代码中何时调用了任何方法?
【发布时间】:2013-01-30 12:09:50
【问题描述】:

只是为了好玩,我想写一个方面,比如日志记录、跟踪或检测/分析。但我不想使用任何已经可用的 AOP 框架。

我过去使用过 PostSharp,现在 ASP.NET MVC 引入了动作过滤器,它与 aspect/advise 注入非常相似,而 .NET 4 有 CodeContracts,它们也与 aspect 非常相似,我有一个非常清楚我希望方面 API 的外观。

唯一我还没有弄清楚,并且我相信它是构建 AOP 库的核心,是如何知道何时调用了一个方法?

什么,我要一直看调用堆栈吗?我是否查找主 UI 线程及其同步上下文以查看它是否已分配一些工作,即是否已获得进入的方法?有什么方法可以知道一个方法是否会被调用?

【问题讨论】:

    标签: c# .net .net-4.0 aop


    【解决方案1】:

    有两种方法可以知道一个方法是否会被调用。

    1. 您可以从 ContextBoundObject 继承,但您失去了基类的唯一机会。可以查看this

    2. 您可以继承您的类并覆盖您的方法。新方法可以在调用基方法之前调用拦截器。幸运的是,这个派生类可以在运行时构建。实际上,这就是 Castle 的 DynamicProxy 所做的。详细地说,您构建一个继承您的类的类型,以便在运行时拦截并实例化这个派生类。您将 IL 代码发送到新生成的类的方法中。

    我不知道是否允许粘贴长代码,但这是我编写的 DynamicProxy 的一个小版本。它依赖的唯一库是System。你可以这样使用它。

    // typeof obj: public class TestClassProxy : TestClass, IInterface1, IIterface2
    var obj = Proxy.Of<TestClass>(new CallHandler(), typeof(IInterface1), typeof(IInterface2));
    
    obj.MethodVoid();
    Console.WriteLine(obj.PublicSquare(3));
    Console.WriteLine(obj.MethodString());
    

    一个处理方法被触发:

    1. 调用方法之前 (BeforeMethodCall)
    2. 调用方法后(AfterMethodCall)
    3. 如果方法发生异常(OnError)

    所有这些方法都接受参数、具有该方法的对象、当前方法的 MethodInfo 以及传递给方法的参数。另外,AfterMethodCall 接受返回值,OnError 接受抛出的异常。

    这是神奇的Proxy

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Reflection.Emit;
    
    namespace emit
    {
    public class Proxy
    {
        #region static
    
        private static readonly AssemblyBuilder AssemblyBuilder;
        private static readonly ModuleBuilder ModuleBuilder;
    
        private static readonly object LockObj = new Object();
        private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
    
        static Proxy()
        {
            lock (LockObj)
            {
                AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
                    new AssemblyName("Taga.Proxies"),
                    AssemblyBuilderAccess.Run);
    
                var assemblyName = AssemblyBuilder.GetName().Name;
    
                ModuleBuilder = AssemblyBuilder.DefineDynamicModule(assemblyName);
            }
        }
    
        private static Type GetImplementedType(Type baseType, Type[] interfaceTypes)
        {
            var key = GetTypeKey(baseType, interfaceTypes);
            return TypeCache.ContainsKey(key) ? TypeCache[key] : null;
        }
    
        private static void AddImplementation(Type baseType, Type[] interfaceTypes, Type implementationType)
        {
            var key = GetTypeKey(baseType, interfaceTypes);
            TypeCache.Add(key, implementationType);
        }
    
        private static string GetTypeKey(Type baseType, Type[] interfaceTypes)
        {
            var key = String.Empty;
            key += baseType.FullName;
            key = interfaceTypes.Aggregate(key, (current, interfaceType) => current + interfaceType);
            return key;
        }
    
        public static TBase Of<TBase>(ICallHandler callHandler, params Type[] interfaceTypes) where TBase : class
        {
            var builder = new Proxy(typeof(TBase), interfaceTypes);
            var type = builder.GetProxyType();
            return (TBase)Activator.CreateInstance(type, callHandler);
        }
    
        public static object Of(ICallHandler callHandler, Type[] interfaceTypes)
        {
            if (interfaceTypes == null || interfaceTypes.Length == 0)
                throw new InvalidOperationException("No interface type specified");
            return Of<object>(callHandler, interfaceTypes);
        }
    
        #endregion
    
        #region Proxy
    
        private TypeBuilder _typeBuilder;
        private FieldBuilder _callHandlerFieldBuilder;
        private readonly Type _baseClassType;
        private readonly Type[] _interfaceTypes;
    
        private Proxy(Type baseClassType, Type[] interfaceTypes)
        {
            if (interfaceTypes == null || !interfaceTypes.Any())
                _interfaceTypes = Type.EmptyTypes;
            else if (interfaceTypes.Any(it => !it.IsInterface || !it.IsPublic || it.IsGenericType))
                throw new InvalidOperationException("Interface Types must be public and non generic");
            else
                _interfaceTypes = interfaceTypes;
    
            if (baseClassType == null)
                _baseClassType = typeof(object);
            else if (!baseClassType.IsClass || baseClassType.IsAbstract || baseClassType.IsGenericType || baseClassType.IsSealed || !baseClassType.IsPublic || !baseClassType.HasDefaultConstructor())
                throw new InvalidOperationException("Base Class Type must be a public, non-sealed, non-abstract, non-generic class with a public default constructor");
            else
                _baseClassType = baseClassType;
        }
    
        private string _typeName;
        private string TypeName
        {
            get { return _typeName ?? (_typeName = BuildTypeName()); }
        }
    
        private string BuildTypeName()
        {
            var typeName = "__";
    
            if (_baseClassType != null)
                typeName += _baseClassType.Name + "__";
    
            foreach (var interfaceType in _interfaceTypes)
                typeName += interfaceType.Name + "__";
    
            return typeName + "Proxy__";
        }
    
        private Type GetProxyType()
        {
            var type = GetImplementedType(_baseClassType, _interfaceTypes);
            if (type != null)
                return type;
    
            type = BuildType();
    
            AddImplementation(_baseClassType, _interfaceTypes, type);
            return type;
        }
    
        private Type BuildType()
        {
            InitTypeBuilder();
            DefineCallHandlerField();
            BuildConstructor();
            ExtendBase();
            ImplementInterfaces();
    
            return _typeBuilder.CreateType();
        }
    
        private void InitTypeBuilder()
        {
            // public class __BaseClass__Interface1__Interface2__Proxy__ : BaseClass, Interface1, Interface2
            _typeBuilder = ModuleBuilder.DefineType(
                TypeName,
                TypeAttributes.Public | TypeAttributes.Class,
                _baseClassType,
                _interfaceTypes);
        }
    
        private void DefineCallHandlerField()
        {
            // private ICallHandler _callHandler;
            _callHandlerFieldBuilder = _typeBuilder.DefineField("_callHandler", typeof(ICallHandler), FieldAttributes.Private);
        }
    
        private void BuildConstructor()
        {
            var constructorBuilder = DeclareContsructor();   // public ProxyClass(ICallHandler callHandler)
            ImplementConstructor(constructorBuilder);       // : base() { this._callHandler = callHandler; }
        }
    
        private void ExtendBase()
        {
            foreach (var mi in _baseClassType.GetVirtualMethods())
                BuildMethod(mi);
        }
    
        private void ImplementInterfaces()
        {
            foreach (var methodInfo in _interfaceTypes.SelectMany(interfaceType => interfaceType.GetMethods()))
                BuildMethod(methodInfo);
        }
    
        private ConstructorBuilder DeclareContsructor()
        {
            var constructorBuilder = _typeBuilder.DefineConstructor(
                MethodAttributes.Public,
                CallingConventions.HasThis,
                new[] { typeof(ICallHandler) });
            return constructorBuilder;
        }
    
        private void ImplementConstructor(ConstructorBuilder constructorBuilder)
        {
            var baseCtor = _baseClassType.GetConstructor(Type.EmptyTypes);
    
            var il = constructorBuilder.GetILGenerator();
    
            // call base ctor
            il.Emit(OpCodes.Ldarg_0); // push this
            il.Emit(OpCodes.Call, baseCtor); // Call base constructor this.base(); pops this
    
            // set _callHandler
            il.Emit(OpCodes.Ldarg_0); // push this
            il.Emit(OpCodes.Ldarg_1); // push callHandler argument
            il.Emit(OpCodes.Stfld, _callHandlerFieldBuilder); // this._callHandler = callHandler, pop this, pop callhandler argument
    
            il.Emit(OpCodes.Ret); // exit ctor
        }
    
        private void BuildMethod(MethodInfo mi)
        {
            var methodBuilder = CallHandlerMethodBuilder.GetInstance(_typeBuilder, mi, _callHandlerFieldBuilder);
            methodBuilder.Build();
        }
    
        #endregion
    }
    
    class CallHandlerMethodImplementor : CallHandlerMethodBuilder
    {
        internal CallHandlerMethodImplementor(TypeBuilder typeBuilder, MethodInfo methodInfo, FieldBuilder callHandlerFieldBuilder)
            : base(typeBuilder, methodInfo, callHandlerFieldBuilder)
        {
        }
    
        protected override void SetReturnValue()
        {
            // object res = returnValue;
            ReturnValue = IL.DeclareLocal(typeof(object));
            if (MethodInfo.ReturnType != typeof(void))
                IL.Emit(OpCodes.Stloc, ReturnValue); // pop return value of BeforeCall into res
            else
                IL.Emit(OpCodes.Pop); // pop return value of BeforeCall
        }
    }
    
    class CallHandlerMethodOverrider : CallHandlerMethodBuilder
    {
        internal CallHandlerMethodOverrider(TypeBuilder typeBuilder, MethodInfo methodInfo, FieldBuilder callHandlerFieldBuilder)
            : base(typeBuilder, methodInfo, callHandlerFieldBuilder)
        {
        }
    
        protected override void SetReturnValue()
        {
            // ReturnValue = base.Method(args...)
            CallBaseMethod();
            // stack'ta base'den dönen değer var
            SetReturnValueFromBase();
        }
    
        private void CallBaseMethod()
        {
            IL.Emit(OpCodes.Pop); // pop return value of BeforeCall
    
            // base'den Method'u çağır
            // returnValue = base.Method(params...)
            IL.Emit(OpCodes.Ldarg_0); // push this 
            for (var i = 0; i < ParameterCount; i++)  // metoda gelen parametreleri stack'e at
                IL.Emit(OpCodes.Ldarg_S, i + 1);// push params[i]
            IL.Emit(OpCodes.Call, MethodInfo); // base.Method(params) pop this, pop params push return value
        }
    
        private void SetReturnValueFromBase()
        {
            ReturnValue = IL.DeclareLocal(typeof(object));
    
            if (MethodInfo.ReturnType == typeof(void))
                return;
    
            // unbox returnValue if required
            if (MethodInfo.ReturnType.IsValueType)
                IL.Emit(OpCodes.Box, MethodInfo.ReturnType);
            IL.Emit(OpCodes.Stloc, ReturnValue); // pop return value into res
        }
    }
    
    abstract class CallHandlerMethodBuilder
    {
        private ParameterInfo[] _parameters;
        private MethodBuilder _methodBuilder;
        private readonly TypeBuilder _typeBuilder;
        private readonly FieldBuilder _callHandlerFieldBuilder;
    
        protected readonly MethodInfo MethodInfo;
    
        protected ILGenerator IL { get; private set; }
        protected int ParameterCount { get; private set; }
    
        private MethodInfo _beforeCall;
        private MethodInfo BeforeCall
        {
            get
            {
                return _beforeCall ?? (_beforeCall = typeof(ICallHandler).GetMethods().First(m => m.Name == "BeforeMethodCall"));
            }
        }
    
        private MethodInfo _afterCall;
        private MethodInfo AfterCall
        {
            get
            {
                return _afterCall ?? (_afterCall = typeof(ICallHandler).GetMethods().First(m => m.Name == "AfterMethodCall"));
            }
        }
    
        private MethodInfo _onError;
        private MethodInfo OnError
        {
            get
            {
                return _onError ?? (_onError = typeof(ICallHandler).GetMethods().First(m => m.Name == "OnError"));
            }
        }
    
        protected CallHandlerMethodBuilder(TypeBuilder typeBuilder, MethodInfo methodInfo, FieldBuilder callHandlerFieldBuilder)
        {
            _typeBuilder = typeBuilder;
            MethodInfo = methodInfo;
            _callHandlerFieldBuilder = callHandlerFieldBuilder;
        }
    
        private void Declare()
        {
            // public override? ReturnType Method(arguments...)
            _methodBuilder = _typeBuilder.DefineMethod(MethodInfo.Name,
                                                          MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual,
                                                          MethodInfo.ReturnType,
                                                          MethodInfo.GetParameterTypes());
            IL = _methodBuilder.GetILGenerator();
    
            _parameters = MethodInfo.GetParameters();
            ParameterCount = _parameters.Length;
        }
    
        private LocalBuilder _objParameter;
        private void SetObjectParameter()
        {
            // CallHandlera verilecek object obj
            _objParameter = IL.DeclareLocal(typeof(object)); // object obj;
            IL.Emit(OpCodes.Ldarg_0); // push this
            IL.Emit(OpCodes.Stloc, _objParameter); // obj = this; pops this
        }
    
        private LocalBuilder _methodInfoParameter;
        private void SetMethodInfoParameter()
        {
            // CallHandlera verilecek MethodInfo methodInfo
            _methodInfoParameter = IL.DeclareLocal(typeof(MethodInfo)); // MethodInfo methodInfo;
            IL.Emit(OpCodes.Ldtoken, MethodInfo);
            IL.Emit(OpCodes.Call, typeof(MethodBase).GetMethod(
                "GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle) })); // MethodBase.GetMethodFromHandle(new RuntimeMethodHandle());
            IL.Emit(OpCodes.Stloc, _methodInfoParameter);
        }
    
        private LocalBuilder _argsParameter;
        private void SetArgsParameters()
        {
            // CallHandlera verilecek object[] args
            _argsParameter = IL.DeclareLocal(typeof(object[])); // object[] args;
            IL.Emit(OpCodes.Ldc_I4, ParameterCount); // push parameterCount as Int32
            IL.Emit(OpCodes.Newarr, typeof(object)); // push new object[parameterCount]; pops parameterCount
            IL.Emit(OpCodes.Stloc, _argsParameter); // args = new object[ParameterCount]; pops new object[parameterCount]
    
            // Metoda gelen parametreleri args'a doldur
            for (var i = 0; i < ParameterCount; i++)
            {
                var parameterInfo = _parameters[i];
    
                IL.Emit(OpCodes.Ldloc, _argsParameter); // push args
                IL.Emit(OpCodes.Ldc_I4, i); // push i
                IL.Emit(OpCodes.Ldarg_S, i + 1); // push params[i]; pops i; metoda gelen parametrelerin i'incisi. 0'ıncı parametre this olduğu için  "+1" var
                if (parameterInfo.ParameterType.IsPrimitive || parameterInfo.ParameterType.IsValueType)
                    IL.Emit(OpCodes.Box, parameterInfo.ParameterType); // (object)params[i]
                IL.Emit(OpCodes.Stelem_Ref); // args[i] = (object)params[i]; pops params[i]
            }
        }
    
        private void Try()
        {
            IL.BeginExceptionBlock(); // try {
        }
    
        private void InvokeBeforeMethodCall()
        {
            // this._callHandler.BeforeCall(obj, methodInfo, args);
            IL.Emit(OpCodes.Ldarg_0); // push this
            IL.Emit(OpCodes.Ldfld, _callHandlerFieldBuilder); // push _callHandler; pops this
            IL.Emit(OpCodes.Ldloc, _objParameter); // push obj
            IL.Emit(OpCodes.Ldloc, _methodInfoParameter); // push methodInfo 
            IL.Emit(OpCodes.Ldloc, _argsParameter); // push args
            IL.Emit(OpCodes.Call, BeforeCall); // _callHandler.BeforeCall(obj, methodInfo, args); push return value
        }
    
        protected LocalBuilder ReturnValue;
        protected abstract void SetReturnValue();
    
        private void InvokeAfterMethodCall()
        {
            // this._callHandler.AfterCall(obj, methodInfo, args, returnValue);
            IL.Emit(OpCodes.Ldarg_0); // push this
            IL.Emit(OpCodes.Ldfld, _callHandlerFieldBuilder); // push _callHandler; pops this
            IL.Emit(OpCodes.Ldloc, _objParameter); // push obj
            IL.Emit(OpCodes.Ldloc, _methodInfoParameter); // push methodInfo 
            IL.Emit(OpCodes.Ldloc, _argsParameter); // push args
            IL.Emit(OpCodes.Ldloc, ReturnValue); // push res
            IL.Emit(OpCodes.Call, AfterCall); // _callHandler.AfterCall(obj, methodInfo, args, returnValue); push return value (void değilse)
        }
    
        private void Catch()
        {
            var ex = IL.DeclareLocal(typeof(Exception)); 
    
            IL.BeginCatchBlock(typeof(Exception));          // catch 
            IL.Emit(OpCodes.Stloc_S, ex);                   // (Exception ex) {
            InvokeOnError(ex);                              //     _callHandler.AfterCall(obj, methodInfo, args);
            IL.EndExceptionBlock();                         // }
        }
    
        private void InvokeOnError(LocalBuilder exception)
        {
            // this._callHandler.OnError(obj, methodInfo, args);
            IL.Emit(OpCodes.Ldarg_0); // push this
            IL.Emit(OpCodes.Ldfld, _callHandlerFieldBuilder); // push _callHandler; pops this
            IL.Emit(OpCodes.Ldloc, _objParameter); // push obj
            IL.Emit(OpCodes.Ldloc, _methodInfoParameter); // push methodInfo 
            IL.Emit(OpCodes.Ldloc, _argsParameter); // push args
            IL.Emit(OpCodes.Ldloc, exception); // push ex
            IL.Emit(OpCodes.Call, OnError); // _callHandler.AfterCall(obj, methodInfo, args);
        }
    
        private void Return()
        {
            if (MethodInfo.ReturnType != typeof(void))
            {
                IL.Emit(OpCodes.Ldloc, ReturnValue); // push returnValue
                IL.Emit(OpCodes.Unbox_Any, MethodInfo.ReturnType); // (ReturnType)returnValue
            }
    
            IL.Emit(OpCodes.Ret); // returns the value on the stack, if ReturnType is void stack should be empty
        }
    
        internal void Build()
        {
            Declare();                   // public override? ReturnType Method(arguments...) {
            SetObjectParameter();        //     object obj = this;
            SetMethodInfoParameter();    //     MethodInfo methodInfo = MethodBase.GetMethodFromHandle(new RuntimeMethodHandle());
            SetArgsParameters();         //     object[] args = arguments;
            Try();                       //     try {
            InvokeBeforeMethodCall();    //         object returnValue = _callHandler.BeforeMethodCall(obj, methodInfo, args);
            SetReturnValue();            //         !IsAbstract => returnValue = (object)base.Method(arguments);
            InvokeAfterMethodCall();     //         _callHandler.AfterMethodCall(obj, methodInfo, args, returnValue);
            Catch();                     //      } catch (Exception ex) { _callHandler.OnError(obj, methodInfo, args, ex); }
            Return();                    //     IsVoid ? (return;) : return (ReturnType)returnValue; }
        }
    
        internal static CallHandlerMethodBuilder GetInstance(TypeBuilder typeBuilder, MethodInfo methodInfo, FieldBuilder callHandlerFieldBuilder)
        {
            if (methodInfo.IsAbstract)
                return new CallHandlerMethodImplementor(typeBuilder, methodInfo, callHandlerFieldBuilder);
            return new CallHandlerMethodOverrider(typeBuilder, methodInfo, callHandlerFieldBuilder);
        }
    }
    
    public interface ICallHandler
    {
        object  BeforeMethodCall    (object obj, MethodInfo mi, object[] args);
        void    AfterMethodCall     (object obj, MethodInfo mi, object[] args, object returnValue);
        void    OnError             (object obj, MethodInfo mi, object[] args, Exception exception);
    }
    
    static class ReflectionExtensions
    {
        public static bool HasDefaultConstructor(this Type type)
        {
            return type.GetConstructors(BindingFlags.Public | BindingFlags.Instance).Any(ctor => !ctor.GetParameters().Any());
        }
    
        public static Type[] GetParameterTypes(this MethodInfo methodInfo)
        {
            return methodInfo.GetParameters().Select(pi => pi.ParameterType).ToArray();
        }
    
        public static MethodBuilder GetMethodBuilder(this TypeBuilder typeBuilder, MethodInfo mi)
        {
            // MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual
            return typeBuilder.DefineMethod(mi.Name, mi.Attributes, mi.ReturnType, mi.GetParameterTypes());
        }
    
        public static MethodInfo[] GetVirtualMethods(this Type type)
        {
            return type.GetMethods().Where(mi => mi.IsVirtual).ToArray();
        }
    
        public static object GetDefaultValue(this Type t)
        {
            return typeof(ReflectionExtensions).GetMethod("Default").MakeGenericMethod(t).Invoke(null, null);
        }
    
        public static T Default<T>()
        {
            return default(T);
        }
    }
    }
    

    这是测试代码

    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Reflection;
    using System.Threading;
    
    namespace emit
    {
    public class Program
    {
        private static void Main()
        {
            Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");
            try
            {
                TestProxy();
                Console.WriteLine("OK");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            Console.ReadLine();
        }
    
        private static void TestProxy()
        {
            var obj = Proxy.Of<TestClass>(new CallHandler(), typeof(IInterface1), typeof(IInterface2));
    
            obj.MethodVoid();
            Console.WriteLine();
            Console.WriteLine(obj.PublicSquare(3));
            Console.WriteLine();
            Console.WriteLine(obj.MethodString());
            Console.WriteLine();
            Console.WriteLine(obj.MethodInt());
            Console.WriteLine();
            Console.WriteLine(obj.MethodComplex(45, " Deneme ", new Ogrenci { Name = "Ali" }).Name);
            Console.WriteLine();
            obj.PropInt = 78;
            Console.WriteLine();
            Console.WriteLine(obj.PropInt);
            Console.WriteLine();
    
            var int1 = obj as IInterface1;
            int1.Name = "Interface";
            Console.WriteLine();
            Console.WriteLine("Got: " + int1.Name);
            Console.WriteLine();
            int1.Name = "Interface333";
            Console.WriteLine();
            Console.WriteLine("Got3: " + int1.Name);
            Console.WriteLine();
            Console.WriteLine(int1.MethodString(34, "Par", new Ogrenci { Name = "Veli" }));
    
            var int2 = obj as IInterface2;
            int2.Value = 14;
            Console.WriteLine();
            Console.WriteLine("Got: " + int2.Value);
            Console.WriteLine();
            int2.Value = 333;
            Console.WriteLine();
            Console.WriteLine("Got3: " + int2.Value);
            Console.WriteLine();
            Console.WriteLine(int2.MethodInt(34, "Par", new Ogrenci { Name = "Veli" }));
            Console.WriteLine();
    
            obj.ThrowException();
        }
    }
    
    public class CallHandler : ICallHandler
    {
        private readonly SortedDictionary<string, object> _propertyValues = new SortedDictionary<string, object>();
    
        public object BeforeMethodCall(object obj, MethodInfo mi, object[] args)
        {
            WriteParameterInfo(mi, args);
            return SetReturnValue(mi, args);
        }
    
        public void AfterMethodCall(object obj, MethodInfo mi, object[] args, object returnValue)
        {
            if (mi.ReturnType == typeof(void))
                Console.WriteLine(mi.Name + " returns [void]");
            else
                Console.WriteLine(mi.Name + " returns [" + (returnValue ?? "null") + "]");
        }
    
        public void OnError(object obj, MethodInfo mi, object[] args, Exception exception)
        {
            Console.WriteLine("Exception Handled: " + exception.Message);
            throw new ApplicationException(exception.Message, exception);
        }
    
        private object SetReturnValue(MethodInfo mi, object[] args)
        {
            object res = null;
    
            if (mi.Name.StartsWith("get_"))
            {
                var propName = mi.Name.Replace("get_", "");
                if (_propertyValues.ContainsKey(propName))
                    res = _propertyValues[propName];
            }
            else if (mi.Name.StartsWith("set_"))
            {
                var propName = mi.Name.Replace("set_", "");
                if (!_propertyValues.ContainsKey(propName))
                    _propertyValues.Add(propName, args[0]);
                else
                    _propertyValues[propName] = args[0];
            }
            else if (mi.IsAbstract && mi.ReturnType != typeof(void))
            {
                res = mi.ReturnType.GetDefaultValue();
                var methodName = mi.Name;
                if (!_propertyValues.ContainsKey(methodName))
                    _propertyValues.Add(methodName, res);
                else
                    _propertyValues[methodName] = res;
            }
    
            if (mi.ReturnType == typeof(void))
                Console.WriteLine(mi.Name + " should return [void]");
            else
                Console.WriteLine(mi.Name + " should return [" + res + "]");
    
            return res;
        }
    
        private void WriteParameterInfo(MethodInfo mi, object[] args)
        {
            Console.Write(mi.Name + " takes ");
            if (args.Length == 0)
            {
                Console.WriteLine("no parameter");
            }
            else
            {
                Console.WriteLine("{0} parameter(s)", args.Length);
                var paramInfos = mi.GetParameters();
                for (int i = 0; i < args.Length; i++)
                {
                    Console.WriteLine("\t[{0} {1}: '{2}']", paramInfos[i].ParameterType.Name, paramInfos[i].Name, args[i]);
                }
            }
        }
    }
    
    public interface IInterface1
    {
        string Name { get; set; }
        string MethodString(int i, string s, object o);
    }
    
    public interface IInterface2
    {
        int Value { get; set; }
        int MethodInt(int i, string s, Ogrenci o);
    }
    
    public class TestClass
    {
        public virtual int PropInt { get; set; }
    
        public virtual void ThrowException()
        {
            throw new Exception("Custom Error");
        }
    
        protected virtual double ProtectedSquare(int x)
        {
            Console.WriteLine("Executing Method ProtectedSquare");
            return x * x;
        }
    
        public virtual double PublicSquare(int x)
        {
            Console.WriteLine("Executing Method PublicSquare");
            return ProtectedSquare(x);
        }
    
        public virtual string MethodString()
        {
            Console.WriteLine("Executing String Method");
            return "Hele";
        }
    
        public virtual int MethodInt()
        {
            Console.WriteLine("Executing Int Method");
            return 985;
        }
    
        public virtual void MethodVoid()
        {
            Console.WriteLine("Executing Void Method");
        }
    
        public virtual Ogrenci MethodComplex(int x, string f, Ogrenci o)
        {
            Console.WriteLine("Executing Parameter Method");
            return new Ogrenci { Name = o.Name + x + f };
        }
    }
    
    public class Ogrenci
    {
        public string Name { get; set; }
    
        public override string ToString()
        {
            return Name;
        }
    }
    }
    

    【讨论】:

      【解决方案2】:

      放置一个断点和你想查看它是否被调用的方法

      【讨论】:

        【解决方案3】:

        如果只是每次都下一个断点是不够的:

        如您所说,请注意调用堆栈。只需在您认为合适的时候放置一个断点。

        在 Visual Studio 中这很简单。只需运行程序,当你想要一个断点时,将它设置在你知道即将发生的行中的调试中间。

        第三个选项是调用Console.WriteLineMSDN,即使它不是控制台应用程序。 您将在 Output Window (Ctrl + W, O) 中看到结果。

        您也可以使用System.Diagnostics.TraceMSDN 在输出窗口中写入。

        【讨论】:

          【解决方案4】:

          以上技巧也不错,

          你也可以在你的方法中加入 JavaScript 的警告框。这样你就会知道调用的方法。

          如果您想维护日志,您可以在数据库中创建日志表,并将插入查询与系统时间放在日志表的日志时间列中。因此,您现在将在过去调用您的方法时。

          【讨论】:

            猜你喜欢
            • 2015-05-27
            • 2013-10-01
            • 2023-03-28
            • 2020-12-03
            • 1970-01-01
            • 2020-11-25
            • 1970-01-01
            • 2014-01-29
            • 2011-03-10
            相关资源
            最近更新 更多