我想在基类中包含的受保护的Hashtable中存储在派生类中声明的属性的一些支持字段。 在派生类中使用此机制必须尽可能简单。
那么,我可以使用MethodBase.GetCurrentMethod()
来提供有关调用属性的信息(getter - 属性是只读的),因此它可以被识别为唯一可以访问此特定支持字段的属性吗? / p>
修改
基本上,我想实现模式:
private SomeClass _someProperty = null;
private SomeClass SomeProperty
{
if (_someProperty == null)
{
_someProperty = new SomeClass();
}
return _someProperty;
}
看起来像这样:
private SomeClass SomeProperty
{
return GetProperty(delegate
{
var someProperty = new SomeClass();
return someProperty;
};
}
在基类中
private System.Collections.Hashtable _propertyFields = new System.Collections.Hashtable();
protected T GetProperty<T>(ConstructorDelegate<T> constructorBody)
{
var method = new System.Diagnostics.StackFrame(1).GetMethod();
if (!_propertyFields.ContainsKey(method))
{
var propertyObject = constructorBody.Invoke();
_propertyFields.Add(method, propertyObject);
}
return (T)_propertyFields[method];
}
protected delegate T ConstructorDelegate<T>();
我想这样做的原因是为了简化属性的使用。 我使用私有属性来创建一些对象并在类中使用它们。但是当我将他们的支持字段存储在同一个类中时,我对它们的属性具有相同的访问权限,因此我(意味着将来会创建一些派生类的用户)可能会意外地使用支持字段而不是属性,< strong>所以我想限制对支持字段的访问,同时允许创建对象并使用它。
我尝试在支持字段上使用ObsoleteAttribute,如下所示:
[Obsolete("Don't use this field. Please use corresponding property instead.")]
private SomeClass __someProperty;
private SomeClass _someProperty
{
#pragma warning disable 0618 //Disable Obsolete warning for property usage.
get
{
if (__someProperty== null)
{
__someProperty = new SomeClass();
}
return __someProperty ;
}
#pragma warning restore 0618 //Restore Obsolete warning for rest of the code.
}
但是,首先,我不能强迫用户使用这种模式,其次,要在派生类中编写很多代码,如上所述,我希望尽可能简单。
答案 0 :(得分:2)
MethodBase
和MemberInfo
都未正确覆盖Equals
和GetHashCode
个函数,但使用默认RuntimeHelpers.GetHashCode
和RuntimeHelpers.Equals
。因此,您只能比较相同的实例,但不能比较相同的内容。在大多数情况下,这将足以作为运行时缓存实例以重用它们。但是不能保证它能稳定运行。
在处理元数据时,请使用能够唯一标识元数据的内容。例如,MemberInfo.MetadataToken
。您可以编写自己的比较器并在哈希表中使用它:
public class MethodBaseComparer : IEqualityComparer<MethodBase>
{
public bool Equals(MethodBase x, MethodBase y)
{
if (ReferenceEquals(x, y))
return true;
if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
return false;
return x.MetadataToken.Equals(y.MetadataToken) &&
x.MethodHandle.Equals(y.MethodHandle);
}
public int GetHashCode(MethodBase obj)
{
return (obj.MetadataToken.GetHashCode() * 387) ^ obj.MethodHandle.GetHashCode();
}
}
通过反射将访问限制为某些成员并不是一个好主意,因为其他受信任的代码可以使用反射来访问包围您的支票的其他私有数据。通过重新设计类来考虑限制访问。
另请查看Code Access Security。
根据您的修改更新。
您告诉您的属性是只读的。我想,简单地将它们声明为readonly
不是你的选择。看起来你想要延迟初始化属性值。在这种情况下,您将无法将它们声明为readonly
。正确?
或者你可以吗?
看看Lazy<T>
课程。它在dotnet 2.0中不可用,但您可以轻松实现它,甚至可以使用any existing implementation (just replace Func<T>
with your delegate)。用法示例:
public class Foo
{
private readonly Lazy<int> _bar = new Lazy<int>(() => Environment.TickCount, true);
// similar to your constructorBody - ^^^^^^^^^^^^^^^^^^^^^^^^^^^
private int Bar
{
get { return this._bar.Value; }
}
public void DoSomethingWithBar(string title)
{
Console.WriteLine("cur: {0}, foo.bar: {1} <- {2}",
Environment.TickCount,
this.Bar,
title);
}
}
<强>赞成强>:
这是一个懒惰的初始化,如你所愿。我们来测试一下:
public static void Main()
{
var foo = new Foo();
Console.WriteLine("cur: {0}", Environment.TickCount);
Thread.Sleep(300);
foo.DoSomethingWithBar("initialization");
Thread.Sleep(300);
foo.DoSomethingWithBar("later usage");
}
输出将是这样的:
cur: 433294875
cur: 433295171, foo.bar: 433295171 <- initialization
cur: 433295468, foo.bar: 433295171 <- later usage
注意,首次访问时初始化的值,以后不会更改。
属性受编译器的写保护 - _bar
字段为readonly
,您无法访问Lazy<T>
的内部字段。因此,没有任何意外的支持字段使用。如果您尝试,将在类型不匹配时收到编译错误:
CS0029无法将
System.Lazy<SomeClass>
类型隐式转换为SomeClass
即使您通过this._bar.Value
访问它,也不会发生任何可怕的事情,您将获得正确的值,就像通过this.Bar
属性访问它一样。
它更简单,更快速,更易于阅读和维护。
开箱即用的线程安全。
缺点: - (我没找到)
基于hashtable
的设计的几分钱: