如何使用继承缓存类的静态数据



想象一下,你正在制作一个使用某种纹理的游戏对象:

public class Action {
    //This two can (must) be overriden
    public const string _HoverCursor = "Textures/cursors/select";
    public virtual string HoverCursor { get { return _HoverCursor; } }
    //This is the get texture by string
    private static Texture2D cursorTex = null;
    public static Texture2D cursor { get { return ResourceManager.loadTexture(ref cursorTex, HoverCursor); } }
}

如果传递了null,则loadTexture函数将加载纹理。否则,它只返回原始值。

正如你所看到的,我正在制作一个动作原型。将有类似攻击移动构建的操作。我想为每个类定义存储一个(和不同的)纹理对象。当需要使用上面的getter时,这个对象应该是惰性加载的。

既然静态属性不能被覆盖,我如何为所有子实例实现它?

这是loadTexture:

    public static Texture2D loadTexture(ref Texture2D target, string name)
    {
        if (target == null)
        {
            target = (Texture2D)Resources.Load(name, typeof(Texture2D));
        }
        return target;
    }

您可以对实例成员使用继承和多态性,并使用静态工厂方法作为外观来简化实现的实例化。

例如

public abstract class Action
{
    public abstract void LoadTexture(...);
}
// Since static façade class has a generic type parameter, we're talking
// about a completely different class than just "Action" and both can co-exist!
public static class Action<TAction> where TAction : Action, new()
{
    public static Texture2D LoadTexture(...)
    { 
        // Since generic TAction parameter must implement a public parameterless
        // constructor, you may instantiate T like a concrete class:
        return new TAction().LoadTexture(...);
    }
}

因此,您将使用如下静态方法:

Texture2D texture = Action<CustomAction>.LoadTexture2D(...);

您实际上已经自己回答了这个问题:

既然静态属性不能被覆盖,我如何为所有子实例实现它?

只需将属性设置为实例属性即可。例如:

public class Action {
    //This two can (must) be overriden
    public const string _HoverCursor = "Textures/cursors/select";
    public virtual string HoverCursor { get { return _HoverCursor; } }
    //This is the get texture by string
    private static Texture2D cursorTex = null;
    public virtual Texture2D cursor
    {
        get
        {
            return ResourceManager.loadTexture(ref cursorTex, HoverCursor);
        }
    }
}
public class Attack {
    //This two can (must) be overriden
    public const string _HoverCursor = "Textures/cursors/attack";
    public virtual string HoverCursor { get { return _HoverCursor; } }
    //This is the get texture by string
    private static Texture2D cursorTex = null;
    public override Texture2D cursor
    {
        get
        {
            return ResourceManager.loadTexture(ref cursorTex, HoverCursor);
        }
    }
}

每个类仍然只保存一个纹理,但如果每个类都有一个实例,则可以检索该类的正确光标纹理。假设您只需要在有类实例的情况下设置光标,所以这不应该是一个不合理的限制。

请注意,在上文中,如果没有其他代码实际需要HoverCursor属性,则可以去掉它,使_HoverCursor常量成为私有成员,然后直接在cursor属性getter中使用它。

还要注意,这个实现不是线程安全的。只要您总是从一个线程访问cursor属性,就可以了。但如果不是(或者可能只是为了简单起见),您可能更喜欢使用Lazy<T>类。例如:

    //This is the get texture by string
    private static Lazy<Texture2D> cursorTex =
        new Lazy<Texture2D>(() => ResourceManager.loadTexture(HoverCursor));
    public virtual Texture2D cursor
    {
        get
        {
            return cursorTex.Value;
        }
    }

在此版本中,请注意,loadTexture()方法已更改为始终加载纹理,因此不需要ref参数。Lazy<T>类将确保线程安全的延迟初始化,每个类只调用loadTexture()一次。

最新更新