在类的所有方法之前运行方法

时间:2012-02-08 11:49:34

标签: c# reflection

是否可以在C#3或4中执行此操作?也许有一些反思?

class Magic
{

    [RunBeforeAll]
    public void BaseMethod()
    {
    }

    //runs BaseMethod before being executed
    public void Method1()
    {
    }

    //runs BaseMethod before being executed
    public void Method2()
    {
    }
}

修改

有一个替代解决方案,使Magic成为单例,并将您的代码放在静态实例的getter上。这就是我所做的:

public class Magic
{

    private static Magic magic = new Magic();
    public static Magic Instance
    {
        get
        {
            magic.BaseMethod();
            return magic;
        }
    }

    public void BaseMethod()
    {
    }

    //runs BaseMethod before being executed
    public void Method1()
    {
    }

    //runs BaseMethod before being executed
    public void Method2()
    {
    }
}

9 个答案:

答案 0 :(得分:11)

你不能在C#中自动执行此操作 - 你应该看看AOP,例如与PostSharp

答案 1 :(得分:9)

有一个替代解决方案,让Magic成为单例,并将您的代码放在静态实例的getter上。这就是我所做的。

public class Magic{

private static Magic magic;
public static Magic Instance{
  get
    {
   BaseMethod();
    return magic;
    }
}

public void BaseMethod(){
}

//runs BaseMethod before being executed
public void Method1(){
}

//runs BaseMethod before being executed
public void Method2(){
}
}

答案 2 :(得分:3)

答案 3 :(得分:2)

我知道它不会直接回答这个问题。但是使用装饰器模式来解决这个问题是一种很好的方法,可以使你的实现保持清洁。

创建界面

public static void showPopup(RichPopup pop, boolean visible) {
    try {
        System.out.println("entered in showPopup code");
        FacesContext context = FacesContext.getCurrentInstance();
        if (context != null && pop != null) {
            //String popupId = pop.getClientId(context);
            String popupId = pop.getId();

            System.out.println("ClientID of popup="+popupId);

            if (popupId != null) {
                System.out.println("Client PopupID is not null");

                StringBuilder script = new StringBuilder();
                script.append("var popup = AdfPage.PAGE.findComponent('").append(popupId).append("'); ");
                if (visible) {
                    script.append("if (!popup.isPopupVisible()) { ").append("popup.show();}");
                } else {
                    script.append("if (popup.isPopupVisible()) { ").append("popup.hide();}");
                }
                ExtendedRenderKitService erks = Service.getService(context.getRenderKit(), ExtendedRenderKitService.class);
                erks.addScript(context, script.toString());
            }
        }
        System.out.println("completion of showPopup code");
    }
    catch (Exception e) {
        System.out.println("exception occured in showPopup code="+e.getMessage());
        throw new RuntimeException(e);
    }
}

创建实施

public interface IMagic
{


    public void Method1()
    {
    }


    public void Method2()
    {
    }
}

创建装饰器

public class Magic : IMagic
{

    public void Method1()
    {
    }


    public void Method2()
    {
    }
}

<强>用法

public class MagicDecorator : IMagic
{
   private IMagic _magic;
   public MagicDecorator(IMagic magic)
   {
       _magic = magic;
   }

   private void BaseMethod()
   {
       // do something important
   }

    public void Method1()
    {
         BaseMethod();
         _magic.Method1();
    }


    public void Method2()
    {
        BaseMethod();
        _magic.Method2();
    }
}

答案 4 :(得分:1)

使用https://github.com/Fody/Fody。许可模式基于自愿捐款,这使其成为PostSharp的更好选择,这对我来说有点贵。

[module: Interceptor]
namespace GenericLogging
{

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Assembly | AttributeTargets.Module)]
    public class InterceptorAttribute : Attribute, IMethodDecorator
    {
        // instance, method and args can be captured here and stored in attribute instance fields
        // for future usage in OnEntry/OnExit/OnException
        public void Init(object instance, MethodBase method, object[] args)
        {
            Console.WriteLine(string.Format("Init: {0} [{1}]", method.DeclaringType.FullName + "." + method.Name, args.Length));
        }

        public void OnEntry()
        {
            Console.WriteLine("OnEntry");
        }

        public void OnExit()
        {
            Console.WriteLine("OnExit");
        }

        public void OnException(Exception exception)
        {
            Console.WriteLine(string.Format("OnException: {0}: {1}", exception.GetType(), exception.Message));
        }
    }

    public class Sample
    {
        [Interceptor]
        public void Method(int test)
        {
            Console.WriteLine("Your Code");
        }
    }
}

[TestMethod]
public void TestMethod2()
{
    Sample t = new Sample();
    t.Method(1);
}

答案 5 :(得分:0)

只是为了清楚说明为什么以下实施无法工作

public class Magic{

private static Magic magic = new Magic();
public static Magic Instance{
  get
    {
   magic.BaseMethod();
    return magic;
    }
}

public void BaseMethod(){
}

//runs BaseMethod before being executed
public void Method1(){
}

//runs BaseMethod before being executed
public void Method2(){
}
}

如果您只想保留Magic个对象,该方法将被随机调用:

Magic m = Magic.Instance; //this will trigger unwanted call on BaseMethod

如果有人想要调用BaseMethod,它将被调用两次:

Magic.Instance.BaseMethod(); //two calls of the BaseMethod

当然有一种解决方法,使用get:

返回不需要的对象
var unused = Magic.Instance;

总结一下:这在C#中是不可能的(至少现在)。

答案 6 :(得分:0)

我最近有理由这样做。除了要说明我希望方法DoThisFirst在我要调用的特定方法之前运行之外,我将为您保留用例的大概无聊的细节。仍在学习C#,所以可能不是最好的方法...

using System;

namespace ConsoleApp1
{
    class Class1
    {
        public enum MethodToCall
        {
            Method2,
            Method3
        }

        public delegate void MyDelegate(int number = 0, bool doThis = false, double longitude = 32.11);

        public static void DoThisFirst(int number, bool doThis, double longitude)
        {
            Console.WriteLine("DoThisFirst has been called.");
        }

        public static void DoSomethingElse(int number, bool doThis, double longitude)
        {
            Console.WriteLine("DoSomethingElse has been called.");
        }

        public static void DoAnotherThing(int number, bool doThis, double longitude)
        {
            Console.WriteLine("DoAnotherThing has been called.");
        }

        public static void Main()
        {
            void Action(MethodToCall methodToCall)
            {
                MyDelegate myDel;

                myDel = new MyDelegate(DoThisFirst);

                switch (methodToCall)
                {
                    case MethodToCall.Method2:
                        myDel += DoSomethingElse;
                        break;
                    case MethodToCall.Method3:
                        myDel += DoAnotherThing;
                        break;
                }

                myDel.Invoke();
            }

            Action(MethodToCall.Method3);

            Console.ReadKey();
        }
    }
}

答案 7 :(得分:0)

是的,可以!使用静态构造函数,它将在引用该类之前运行一次,您可以在其中进行所需的操作。

赞:

public class Magic{

static Magic()
{
    BaseMethod();
}

public void BaseMethod(){
}

//runs BaseMethod before being executed
public void Method1(){
}

//runs BaseMethod before being executed
public void Method2(){
}
}

这是Microsoft文档:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

答案 8 :(得分:0)

如果您使用依赖注入框架来生成实例,那么您可以使用拦截器进行方法调用。

public class CallLogger : IInterceptor
{
    TextWriter _output;

    public CallLogger(TextWriter output)
    {
        _output = output;
    }

    public void Intercept(IInvocation invocation)
    {
        _output.Write("Calling method {0} with parameters {1}... ",
        invocation.Method.Name,
        string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));

        invocation.Proceed();

        _output.WriteLine("Done: result was {0}.", invocation.ReturnValue);
    }
}

您可以查看 autofac 的文档和示例以获取更多信息。 https://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html