像静态字段

时间:2015-09-03 22:38:49

标签: c# inheritance static

这个问题更具理论性,它不是一个问题,它是家庭作业或重要项目的一部分......我问这个问题因为我认为这可能非常方便了解,但我无法找到一个合适的答案。

问题描述:

  • 应该强制从我的抽象类继承的每个类都提供符号图像。

  • 符号不应该是运行时可更改的

  • 实例不应包含图像[以节省内存]

  • 在运行时[可能通过使用反射]通知开发人员的解决方案是不可接受的(这是一个更理论化的问题)

abstract class A
{
    public static abstract Image Symbol{get;}
}
class B:A
{
  //this Field should be forced for every class that inherits from A
  public static override Image Symbol{get{return....}}
}

当然,我可以使用static readonly关键字代替readonly

但这意味着B类的每个实例都会产生额外的图像,因为ProgrammerError允许在构造函数的运行时期间设置字段 ...导致记忆浪费...可能不是一个巨大的记忆浪费,因为会有或多或少的参考浪费,但它仍在浪费东西...... [纠正我,如果我错了。]

那么......使用继承规则如何简单易行?

4 个答案:

答案 0 :(得分:4)

不可能使静态成员成为抽象/虚拟,因为多态性基于实例的实际类型,静态成员不属于特定实例。

我认为这符合您的所有要求:

abstract class A
{
    public abstract Image Symbol{get;}
}
class B:A
{

  private static readonly Image _symbol = ...

  public override Image Symbol{get{return _symbol;}}
}
  • 每个派生类必须实现Symbol,因为它在基类中是抽象的
  • 静态字段是只读的,因此您无法在初始化后对其进行更改
  • 实例不包含图像实例,它在所有类实例中共享
  • (不确定你对最后一个的意思,但是......)

当然,缺点是它需要所有派生类都遵循这种模式。这并不能防止派生类违反某些要求。

答案 1 :(得分:0)

您可以通过密钥在专用类中缓存图像,并为每个继承的类提供密钥:

public class ImageManager
{
    private static Dictionary<string, Image> _images = new Dictionary<string, Image>();
    private static object _locker = new object();
    public static Image GetImageByTypeKey(string key)
    {
        if (!_images.ContainsKey(key))
        {
            lock (_locker) {
                if (!_images.ContainsKey(key))
                {
                    //Add your real loading logic here + handle exceptions (not found, etc...)
                    Image image = Image.FromFile(key + ".png");
                    _images.Add(key,image);
                }
            }
        }
        return _images[key];
    }
}

public abstract class BaseType
{
    public Image Symbol
    {
        get
        {
            return ImageManager.GetImageByTypeKey(SymbolKey);
        }
    }
    protected abstract string SymbolKey { get;  }
}

public class TypeA : BaseType
{
    protected override string SymbolKey
    {
        get { return "TypeA";}
    }
}

答案 2 :(得分:0)

我知道这是一个老问题,但是我只是在研究静态字段和继承,并希望分享我的结果。在我当前的项目中,我在半导体环境中得到了一个复杂的数据结构...因此,我的示例不适合这个问题,但可以正确地演示如何实现某种静态场继承。

这是我的解决方法:

第一个解决方法(使用泛型):

public abstract class TESTAbstract 
{
    //overall list of elements
    public static List<TESTAbstract> Elements = new List<TESTAbstract>();
    public static int Count { get; private set; }
    public int localId { get; protected set; }
    public int globalId { get; protected set; }

    //members here
    public int someValue = 0;

    public TESTAbstract()
    {
        globalId = Count; Count++;
        Elements.Add(this);
    }
}



public abstract class TESTAbstract<T> : TESTAbstract where T : TESTAbstract
{
    new public static List<T> Elements = new List<T>();
    new public static int Count { get; private set; }

    public TESTAbstract()
        : base()
    {
        localId = Count; Count++;
        Elements.Add(this as T);
    }
}

实现如下:

public class TEST1 : TESTAbstract<TEST1>
{
    public TEST1(int i)
        : base()
    {
        this.someValue = i;
    }

}

public class TEST2 : TESTAbstract<TEST2>
{
    public TEST2(int i)
        : base()
    {
        this.someValue = i;
    }

}

用法:

            TESTAbstract test1 = new TEST1(1001);
            TESTAbstract test2 = new TEST2(1002);
            TESTAbstract test3 = new TEST2(1003);
            TESTAbstract test4 = new TEST1(1004);
            TESTAbstract test5 = new TEST1(1005);
            TESTAbstract test6 = new TEST1(1006);
            TESTAbstract test7 = new TEST2(1007);
            TESTAbstract test8 = new TEST1(1008);

            Console.WriteLine("All StructureItem Elements: " + TESTAbstract.Elements.Count);
            foreach (var item in TESTAbstract.Elements)
            {
                Console.WriteLine("someValue: " + item.someValue + " localId: " + item.localId + " globalId: " + item.globalId);
            }

            Console.WriteLine("TEST1 Elements: " + TEST1.Elements.Count);
            foreach (var item in TEST1.Elements)
            {
                Console.WriteLine("someValue: " + item.someValue + " localId: " + item.localId + " globalId: " + item.globalId);
            }

            Console.WriteLine("TEST2 Elements: " + TEST2.Count);
            foreach (var item in TEST2.Elements)
            {
                Console.WriteLine("someValue: " + item.someValue + " localId: " + item.localId + " globalId: " + item.globalId);
            }

输出:

All StructureItem Elements: 8
someValue: 1001 localId: 0 globalId: 0
someValue: 1002 localId: 0 globalId: 1
someValue: 1003 localId: 1 globalId: 2
someValue: 1004 localId: 1 globalId: 3
someValue: 1005 localId: 2 globalId: 4
someValue: 1006 localId: 3 globalId: 5
someValue: 1007 localId: 2 globalId: 6
someValue: 1008 localId: 4 globalId: 7
TEST1 Elements: 5
someValue: 1001 localId: 0 globalId: 0
someValue: 1004 localId: 1 globalId: 3
someValue: 1005 localId: 2 globalId: 4
someValue: 1006 localId: 3 globalId: 5
someValue: 1008 localId: 4 globalId: 7
TEST2 Elements: 3
someValue: 1002 localId: 0 globalId: 1
someValue: 1003 localId: 1 globalId: 2
someValue: 1007 localId: 2 globalId: 6

第二种解决方法是使用接口。当您已经从某个类继承并想要添加静态字段时,此功能很有用。

public abstract class Class2 
{
    public int someValue { get; set; }
}


public class TEST3 : Class2, ITest
{
    public TEST3()
    {
        this.AddObj();

    }

}

public class TEST4 : Class2, ITest
{
    public TEST4()
    {
        this.AddObj();
    }

}

public interface ITest{}

然后我使用了接口的通用扩展方法

public static class Class2Ex
{
    public static void AddObj<T>(this T obj) where T : ITest
    {
        ITest<T>.Instances.Add(obj);
    }
    //Alternative:
    public static List<T> GetOtherInstances<T>(this T obj) where T : ITest
    {
        return ITest<T>.Instances;
    }
}

public static class ITest<T> where T : ITest
{
    public static List<T> Instances = new List<T>();
}

示例:

            TEST3 aTest1 = new TEST3();
            TEST3 aTest2 = new TEST3();
            TEST3 aTest3 = new TEST3();
            TEST3 aTest4 = new TEST3();

            TEST4 aTest5 = new TEST4();
            TEST4 aTest6 = new TEST4();

            Console.WriteLine("TEST4: " + ITest<TEST4>.Instances.Count);
            Console.WriteLine("TEST3: " + ITest<TEST3>.Instances.Count);

答案 3 :(得分:-1)

我会在派生类中创建一个静态构造函数。

abstract class A {
  public Image Symbol { get; protected set; }
}
class B:A {
  private static Image SymbolInstance { get; private set; }
  static B() {
    // SymbolInstance = ...
  }
  public B() {
    Symbol = SymbolInstance;
  }
}

只有在启动B类的第一个实例时才会调用静态构造函数。如果您发起20个实例,那无关紧要。

需要测试的一个细节:当从几个派生类设置时,A类中的静态字段是否存在任何引用冲突,或者每个派生类是否都有自己独立的实例?我认为应该没问题,但你必须对它进行测试。

如果要强制派生类来设置字段,可以在基类中进行验证,如果缺少值则抛出异常。