这个问题更具理论性,它不是一个问题,它是家庭作业或重要项目的一部分......我问这个问题因为我认为这可能非常方便了解,但我无法找到一个合适的答案。
问题描述:
应该强制从我的抽象类继承的每个类都提供符号图像。
符号不应该是运行时可更改的
实例不应包含图像[以节省内存]
在运行时[可能通过使用反射]通知开发人员的解决方案是不可接受的(这是一个更理论化的问题)
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
允许在构造函数的运行时期间设置字段
...导致记忆浪费...可能不是一个巨大的记忆浪费,因为会有或多或少的参考浪费,但它仍在浪费东西......
[纠正我,如果我错了。]
那么......使用继承规则如何简单易行?
答案 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类中的静态字段是否存在任何引用冲突,或者每个派生类是否都有自己独立的实例?我认为应该没问题,但你必须对它进行测试。
如果要强制派生类来设置字段,可以在基类中进行验证,如果缺少值则抛出异常。