How to, from static methods ; access a unique valu

2019-08-04 14:11发布

问题:

I want to access the value of a static field in other static methods running on the same thread. An example is in the code below :

The first class in this script is ClassA. ClassA's job is to compare two Rect value , If there is inequality between tho two compared Rect values then a public boolean is set to true;

in classA , IsRectChanged is a bool method which takes a parameter object of type Rect and compares it to StoredRect which is a Rect. The method returns true when storedRect and the Rect value of IsRectChanged do not match.

    public class ClassA
    {
        private Rect storedRect;

        public ClassA() { }

        public bool IsRectChanged(Rect rect)
        {
            bool isChanged = !rect.Equals(storedRect);
            if(isChanged)
            {
                storedRect = rect;
            }

            return isChanged;
        }
    }

This is ClassB We create a static field of ClassA named isRectChanged in ClassB. Do not change the structure of the MethodB in ClassB. Consider the fact that 50 other methods in static and non static classes must use a ClassA field . Needing to change the structure of ClassB in order to make the code work is would be counterproductive.

    public static class ClassB
    {
        private static ClassA RectHelper = new ClassA();

        public static void MethodB(Rect yourRect)
        {
           if(RectHelper.IsRectChanged(yourRect))
           {
               Debug.Log("Changes were made");
           }
        }
    }

ClassC, ClassD and ClassE are running on the same thread.They both call ClassB.MethodB and assign a new Rect in the parameter of MethodB.

Because ClassC ,ClassD and ClassE are call ClassB.MethodB and assign a new Rect in the parameter of MethodB. They each override the storedRect value of the static field ClassA RectHelper.

Because of this ,ClassA RectHelper.IsRectChanged will always be true.

How do I work around this without having to make ClassB's ClassA's and ClassE's MethodB non static ?**

    public class ClassC
    {
        public void UpdateEverFrame()
        {
            ClassB.MethodB(new Rect(0, 0, 20, 20));
        }
    }
    public class ClassD
    {
        public void UpdateEverFrame()
        {
            ClassB.MethodB(new Rect(100, 100, 10, 10));
        }
    }

Here in ClassE ClassB.MthodB is called in two UpdateEverFrame methods , one of which takes in a int parameter . They override each other if they are called simultaneously, so the system will believe that IsRectChanged is true and will always return true. which is a big problem.

We dont want IsRectChanged to be overridden , We want each Call of ClassB.MethodB to be treated as if it are not static so that IsRectChanged is never overridden

    public class ClassE
    {
        public void UpdateEverFrame()
        {
            ClassB.MethodB(new Rect(0, 0, 20, 20));
        }

        public void UpdateEverFrame(int i)
        {
            ClassB.MethodB(new Rect(100, 100, 10, 10));
        }
    }

In my question When I say 'access a unique value of a static property' I am talking about ClassB.RectHelper.

I know that ClassB.RectHelper is STATIC so the value will be shared between the classes ClassC, ClassD and ClassE, whenever they call MethodB. But can we work around this so that ClassC and ClassD so not override the storedRect value in ClassA ?

回答1:

Why don't you just skip the static class B and just make a static property of your class A in your classes C and D. The way you've structured the code seems messed up to me. Another way I would deal with this is to do something like :

public class ClassA
{
    protected Rect storedRect;

    public ClassA() { }

    public virtual void UpdateEverFrame();

    protected bool IsRectChanged(Rect rect)
    {
        bool isChanged = !rect.Equals(StoredRect);
        if(isChanged)
        {
            storedRect = rect;
        }

        return isChanged;
    }
}

public class ClassC : ClassA
{
    public override void UpdateEverFrame()
    {
        if(IsRectChanged(new Rect(0, 0, 20, 20)))
        {
             Debug.Log("Changes were made class C");
        }
    }
}
public class ClassD : ClassA
{
    public override void UpdateEverFrame()
    {
        if(IsRectChanged(new Rect(100, 100, 10, 10)))
        {
             Debug.Log("Changes were made class D");
        }
    }
}


回答2:

I'm not getting the purpose but have you thinked about making ClassB generic? Something like that:

    public class ClassB<T>
    {
        private static ClassA if_rect_Changed = new ClassA();

        public static void MethodB(Rect yourRect)
        {
            if (if_rect_Changed.RectChanged(yourRect))
            {
                Debug.Log("Changes were made");
            }
        }

    }

And use it like it: ClassB<ClassC>.MethodB(rect) so every class will have it's 'copy' of 'change tracker' and you will be able to keep MethodB static.



回答3:

First some clarifications. I am assuming you are using System.Windows.Rect, correct? More clarifications...

We have a static property for ClassA in ClassB called isRectChanged

No, you have a static field of type ClassA in ClassB called RectHelper. IsRectChanged is a non-static method of ClassA.

We want to access the value of a static property in other static methods running on the same thread.

Since they are on the same thread, you have no chance of your static method being called simultaneously. So far, no problem.

They both call ClassB.MethodB and override the value of MethodB's Rect parmeter. Both classes use the same instance of ClassB.MethodB ...

They do not override the Rect parameter, instead they each supply a Rect object. ClassB is the instance, not ClassB.MethodB.

...will always be true.

That is not so, try running the code below and you will see that only the first call returns true.

ClassC c = new ClassC();
c.UpdateEverFrame();
c.UpdateEverFrame();
c.UpdateEverFrame();

But if you insert calls through ClassD between the lines, yes, IsRectChanged will return true because it is true, the Rect is in fact different. But, that is what static is for, i.e., it's for Singleton type operations.

If you want a per class static variable, then put a static variable into each class. If that would require you to duplicate code, then use a template. It doesn't have to be fancy, for instance, simply change ClassB and the calls to ClassB's methods as follows...

public class ClassB<TClass> // the rest of the class is the same
...
/* in ClassC */ ClassB<ClassC>.MethodB(new Rect(...));
...
/* in ClassD */ ClassB<ClassD>.MethodB(new Rect(...));

By making ClassB into a template, each ClassB<> is a different static object each with its own copy of static variables. Now, the following code will return false for all but the first call on ClassC and ClassD.

        ClassC c = new ClassC();
        c.UpdateEverFrame();
        c.UpdateEverFrame();
        c.UpdateEverFrame();
        ClassD d = new ClassD();
        d.UpdateEverFrame();
        d.UpdateEverFrame();
        c.UpdateEverFrame();
        d.UpdateEverFrame();

Here are the classes...

public static class ClassB<TClass>
{
    private static ClassA RectHelper = new ClassA();

    public static void MethodB(Rect yourRect)
    {
        if (RectHelper.IsRectChanged(yourRect))
        {
            Debug.WriteLine("Changes were made");
        }
    }
}

public class ClassC
{
    public void UpdateEverFrame()
    {
        ClassB<ClassC>.MethodB(new Rect(0, 0, 20, 20));
    }
}
public class ClassD
{
    public void UpdateEverFrame()
    {
        ClassB<ClassD>.MethodB(new Rect(100, 100, 10, 10));
    }
}