简体   繁体   中英

How can I make some lines of code to run only one time

Two classes in the same assembly: Class A and Static Class B

In a method of ClassA , I am calling a method in ClassB ,... but I want that to be called only one time and not every single time that I am caling that method of ClassA ... currently I am setting a global property -Ran - to see if that method has been ran before or not...well it works but I feel that this is not the best design. I was wondering if there are better ways to do the same?

Thanks.

ClassA.MyMethod(...)
{
....
//.... 
if (ClassB.Ran != 1)
    ClassB.Foo();
....
//...
}

You need to be careful on how strictly the “only one time” restriction is to be interpreted. Static methods are generally assumed to be thread-safe; if you really want to ensure that your method is only run once, even in the case of racing threads, then you need to use a synchronization mechanism, the simplest example being a lock :

private static bool isRun = false;
private static readonly object syncLock = new object();

public void MyMethod()
{
    lock (syncLock)
    {
        if (!isRun)
        {
            Foo();            
            isRun = true;
        }
    }
}

I would normally do this with Lazy<T>

Consider:

public static class Test // this is your ClassB
{
    private static Lazy<string> m_Property = new Lazy<string>( ()=>
    {
        Console.WriteLine("Lazy invoked"); 
        return "hi";
    },true);
    public static string Property
    {
        get
        {
            Console.WriteLine("value request");
            return m_Property.Value;
        }
    }
}

//....consuming code, this is in your ClassA somewhere

var test1 = Test.Property; // first call, lazy is invoked
var test2 = Test.Property; // cached value is used, delgate not invoked
var test3 = Test.Property; // cached value is used, delgate not invoked
var test4 = Test.Property; // cached value is used, delgate not invoked
var test5 = Test.Property; // cached value is used, delgate not invoked

This is the output:

value request
Lazy invoked
value request
value request
value request
value request

You could use a private static field on the class, so that a result gets set the first time the method is called, preventing it from running again:

class B
{
  private static bool fooRun = false;

  public static void Foo()
  {
    if (fooRun) { return; }
    ...
    fooRun = true;
  }
}

Just pass a bool into the constructor whether or not you want the thing to run? Something like:

ClassA(bool runA)
{
    if (runA) 
    {
        ClassB.Foo();
    }
}

Without any more specifics, it's hard to say, but it sounds like this method in Class B contains some sort of initialization logic. If it's something that just needs to happen the first time Class B is referenced, then you could put it in the static constructor of Class B. If the method in Class B needs to be run only when Class A is referenced, then it could be called from the static constructor of Class A. If it cannot be called until some method of Class A is called, AND it should only ever be called once from anywhere, then I would say you should check a private static variable in Class B from within the method and return immediately if it has already been called. Otherwise, as a last resort, I'd say having a private static variable in Class A would be preferable to a global.

In all of these cases, however, I'd say that you are creating global state, which is almost always indicative of a poor design. In my humble opinion, this kind of problem is just screaming the need for a bit of "dependency injection".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM