gpt4 book ai didi

c# - MethodBase 作为哈希表键

转载 作者:行者123 更新时间:2023-11-30 23:22:58 26 4
gpt4 key购买 nike

我想将派生类中声明的属性的一些支持字段存储在基类中包含的 protected 哈希表中。这种机制在派生类中的使用必须尽可能简单。

那么,我能否使用 MethodBase.GetCurrentMethod() 来提供有关调用属性的信息(getter - 属性是只读的),以便它可以被识别为唯一具有访问权限的属性到这个特定的支持领域?

编辑:

基本上,我想实现模式:

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>();

我这样做的原因是为了简化属性的使用。我使用私有(private)属性来创建一些对象并在类中使用它们。但是当我将它们的支持字段存储在同一个类中时,我对它们的访问权限与对属性的访问权限相同,所以我(指将来会创建一些派生类的用户)可能会不小心使用支持字段而不是属性,< 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.
}

但是,首先,我不能强制用户使用这种模式,其次,在派生类中编写的代码太多,正如我上面提到的,我希望尽可能简单。

最佳答案

都不是MethodBase也不MemberInfo没有正确覆盖 EqualsGetHashCode功能,但使用默认 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();
}
}

通过反射限制对某些成员的访问不是一个好主意,因为其他受信任的代码可以使用反射来访问绕过您的检查的其他私有(private)数据。考虑通过重新设计您的类来限制访问。

另请查看 Code Access Security .

根据您的编辑更新

您告诉您的属性是只读的。我想,只需将它们声明为 readonly 不是你的选择。看起来您想要延迟初始化属性值。在这种情况下,您将无法将它们声明为 readonly .对吧?

也许你可以?

看看 Lazy<T> 类(class)。它在 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);
}
}

优点:

  1. 如您所愿,这是一个惰性初始化。让我们测试一下:

    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

    请注意,值在第一次访问时初始化,以后不会更改。

  2. 属性被编译器写保护 - _bar字段是 readonly并且您无权访问 Lazy<T> 的内部字段.所以,没有任何意外的支持字段使用。如果你尝试你会得到类型不匹配的编译错误:

    CS0029 Cannot implicitly convert type System.Lazy<SomeClass> to SomeClass

    即使您通过 this._bar.Value 访问它,没有什么可怕的事情会发生,你会得到一个正确的值,就像你通过 this.Bar 访问它一样。属性(property)。

  3. 它更简单、更快速、更易于阅读和维护。

  4. 开箱即用的线程安全。

缺点:— (我没找到)

关于您的 hashtable 几分钱|基于设计:

  1. 您(或将维护您的代码的人)可能会不小心(或有意地)访问和/或修改整个哈希表或其项,因为它只是一个普通的私有(private)属性(property)。
  2. Hashtable 对性能影响很小 + 获取堆栈跟踪对性能影响很大。但是我不知道这是否重要,取决于您访问您的属性(property)的频率。
  3. 很难阅读和维护。
  4. 不是线程安全的。

关于c# - MethodBase 作为哈希表键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38589452/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com