0

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

我过去使用过 PostSharp,现在 ASP.NET MVC 引入了动作过滤器,它非常类似于 aspect/advise 注入,而 .NET 4 有 CodeContracts,它们也非常类似于 aspect,我有一个很好的主意我希望我的方面 API 看起来像什么。

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

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

4

4 回答 4

1

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

  1. 您可以从 ContextBoundObject 继承,但您失去了基类的唯一机会。你可以检查这个

  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;
    }
}
}
于 2013-01-30T12:30:22.693 回答
0

如果每次只放置一个断点是不够的:

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

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

第三种选择是调用Console.WriteLineMSDN,即使它不是控制台应用程序。您将在输出窗口( Ctrl+ W, O) 中看到结果。

您还可以使用System.Diagnostics.TraceMSDN在“输出”窗口中进行写入。

于 2013-01-30T12:17:45.330 回答
0

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

于 2013-01-30T12:18:22.187 回答
0

以上招数也不错,

您还可以在您的方法中放置 JavaScript 的警告框。这样你就会知道调用的方法。

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

于 2013-01-30T12:27:27.140 回答