Reputation: 26919
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();
....
//...
}
Upvotes: 4
Views: 9664
Reputation: 43743
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".
Upvotes: 1
Reputation: 17808
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
Upvotes: 8
Reputation: 54877
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;
}
}
}
Upvotes: 9
Reputation: 6356
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;
}
}
Upvotes: 5
Reputation: 56429
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();
}
}
Upvotes: 1