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

问题描述 投票:0回答:9

可以在 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()
    {
    }
}
c# reflection
9个回答
14
投票

您无法在 C# 中自动执行此操作 - 您可能应该查看 AOP,例如与PostSharp


13
投票

对此有一个替代解决方案,使 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(){
}
}

4
投票

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

创建界面

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();
    }
}

用法

var magic = new MagicDecorator(new Magic());
magic.Method1();
magic.Method2();


2
投票

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

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


1
投票

只是为了弄清楚为什么以下实现不起作用

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# 中是不可能的(至少目前)。


1
投票
是的,你可以!使用静态构造函数,它将在引用类之前运行一次,您可以在其中执行您喜欢的操作。

像这样:

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(){ } }

这是微软文档:

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


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); }
    

-1
投票
我最近有理由这样做。我将省去您可能无聊的用例细节,只是声明我希望方法 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(); } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.