我有一个小设计问题,想咨询。 假设我们有以下类层次结构:
abstract class A
{
}
class B : A
{
}
class C: A
{
}
我希望B和C都有一个特定的字段x,这样它的值在各个类之间是不同的,但在同一个类的所有实例之间共享(即:如果b1,b2是B和c1的实例,c2实例是C然后b1.x = b2.x和c1.x = c2.x和b1.x!= c1.x)。 有没有一种优雅的方法来利用B,C派生自相同的基类或者我必须在两个类中创建静态字段x这一事实?
提前致谢。
答案 0 :(得分:4)
你的意思是这样吗?
abstract class A
{
static Dictionary<Type, int> all_x;
protected int X {
get { return all_x[GetType()]; }
set { all_x[GetType()] = value; }
}
}
如果必须是一个字段,那么你可以通过引用传递:
abstract class A
{
class SharedType { int x; }
static Dictionary<Type, SharedType> all_shared;
protected SharedType Shared {
get
{
Type t = GetType();
SharedType result;
if (!all_shared.TryGetValue(t, out result) {
result = new SharedType();
all_shared.Add(t, result);
}
return result;
}
}
}
此外,我们可以通过每个实例只执行一次查询来提高性能:
abstract class A
{
class SharedType { int x; }
static Dictionary<Type, SharedType> all_shared;
protected SharedType Shared;
A() {
Type t = GetType();
if (!all_shared.TryGetValue(t, out Shared) {
Shared = new SharedType();
all_shared.Add(t, Shared);
}
}
}
答案 1 :(得分:0)
我知道这样做的唯一方法是将类A作为泛型类,即类A<T>
。然后让B类为泛型类型实现与C类实现的泛型类型不同的类型。
如果你不使用泛型,那么我相信这在.NET中是不可能的。
这是一个例子,让我们说你感兴趣的值是一个数据结构,成员是int Foo和string Bar。一个派生类可以实现与另一个相同的结构(但是派生类型不同) - 两个结构将实现相同的接口。
interface IAvalue
{
int Foo { get; set;}
string Bar {get; set;}
}
struct BValue
: IAvalue
{
public int Foo { get; set; }
public string Bar { get; set; }
}
struct CValue
: IAvalue
{
public int Foo { get; set; }
public string Bar { get; set; }
}
abstract class A<T> where T : IAvalue
{
protected static T myValue;
}
class B : A<BValue>
{
static B()
{
myValue.Foo = 1;
myValue.Bar = "text1";
}
}
class C : A<CValue>
{
static C()
{
myValue.Foo = 2;
myValue.Bar = "text2";
}
}
答案 2 :(得分:0)
这些值对于字段x应该是什么?如果你需要指定A的x值应为“a”,则B的x值应为“b”等,那么你必须指定值“a”,“b”,..某处,然后你也可以使用:
abstract class A {
public static int x = 1; // Just using "int" as example.
}
class B : A {
public static int x = 2;
}
如果您不关心值是什么(那时您需要哪种类型)但只是希望值“不同”,那么您可以使用以下内容来代替使用字段:
abstract class A {
public int X { get { return this.GetType().GetHashCode(); } }
}
这不会考虑哈希冲突,但也许它有用吗?
你想要实现的目标是什么?
答案 3 :(得分:0)
以Ben Voigt的第一个答案为基础,我认为您对基类的要求是:
public abstract class A
{
private static ConcurrentDictionary<Type, int> _typeIDs = new ConcurrentDictionary<Type, int>();
private static int _nextID = 1;
public int TypeID
{
get
{
return _typeIDs.GetOrAdd(this.GetType(), type => System.Threading.Interlocked.Increment(ref _nextID));
}
}
}
答案 4 :(得分:0)
public abstract class A
{
public abstract int Value { get; }
}
public class B : A
{
public override int Value { get { return 1; } }
}
public class C : A
{
public override int Value { get { return 2; } }
}
答案 5 :(得分:0)
您可以使用一个.net功能:如果您在泛型类中有静态数据成员,.net会为您使用的每种泛型类型创建不同的静态数据成员实例。
所以,你可以写:
public abstract class A<T> where T : A<T>
{
protected static int myVariable { get; set; }
}
继承你的课程:
public class B : A<B>
{
public B()
{
myVariable = 1;
}
public int GetVariable()
{
return myVariable;
}
}
public class C : A<C>
{
public C()
{
myVariable = 2;
}
public int GetVariable()
{
return myVariable;
}
}
然后,B
的每个实例都将拥有对myVariable
的一个实例的共享访问权限,并且C
的每个实例都将拥有对另一个实例的共享权限。
因此,如果您添加Set(int a)
方法:
public void Set(int a)
{
myVariable = a;
}
并运行以下代码:
static void Main(string[] args)
{
B b1 = new B();
C c1 = new C();
B b2 = new B();
C c2 = new C();
Console.Write("{0}; ", b1.GetVariable()); // 1
Console.Write("{0}; ", b2.GetVariable()); // 1
Console.Write("{0}; ", c1.GetVariable()); // 2
Console.Write("{0}; ", c2.GetVariable()); // 2
Console.WriteLine();
c2.Set(333);
Console.Write("{0}; ", b1.GetVariable()); // 1
Console.Write("{0}; ", b2.GetVariable()); // 1
Console.Write("{0}; ", c1.GetVariable()); // 333
Console.Write("{0}; ", c2.GetVariable()); // 333
Console.ReadLine();
}
你得到:1; 1; 2; 2;
1; 1; 333; 333;
输出。
答案 6 :(得分:0)
我建议定义一个静态字典&lt; Type,Integer []&gt;,让基类构造函数自己调用GetType(),看看它是否还在静态字典中。如果没有,请创建一个新的单元素数组并将其存储在字典中。否则从字典中获取数组并将其存储在实例字段中。然后定义一个读取或写入数组元素零的属性。这种方法将实现所有类的衍生物和子衍生物所要求的语义。