繁体   English   中英

自定义属性以缓存 C# 中的只读属性值

[英]Custom Attribute to cache read only Property value in C#

我正在尝试创建一个能够缓存属性值的自定义属性,该属性的类型是IWebElement ,创建起来有点昂贵,并且可能引发NoSuchElement异常。

我已经取得了一些成功,像这样实现它:

protected Lazy<IWebElement> lazyWebElement;
protected virtual IWebElement cachedWebElement
{
    get
    {
        if (!lazyWebElement.IsValueCreated)
        {
            try
            {
                lazyWebElement = new Lazy<IWebElement>(() => driver.FindElement(By.Id("someElement")),
                    LazyThreadSafetyMode.PublicationOnly);
            }
            catch (NoSuchElementException)
            {
                throw new NoSuchElementException("someElement is not present in DOM");
            }
        }

        return lazyModal.Value;
    }
}

而我想做的是

[CachedWebElement]
protected virtual IWebElement cachedWebElement => driver.FindElement(By.Id("someElement"));

但是Attribute不允许在其构造函数中使用复杂类型,因此我无法将driver.FindElement(By.Id("someElement"))作为参数传递。

如果我在派生的 class 中覆盖该属性,那么缓存它会很棒,因为现在我正在使用支持字段来保存值,并且整个机制都会丢失。

谢谢你。

你的方法可能不会很成功。 我的意思是,“只是添加一个属性”。

编译后和运行时,当您检索 object 时(即当您执行类似cachedWebElement.Displayed的操作时),将调用get方法。

构建项目时,所有属性都会get附加到它们的set访问器方法。 您可以在此处找到更多信息microsoft get keyword 基本上, { get; set; } { get; set; } { get; set; }编译成函数,你不能真正“搞砸”。 它们是编译器的默认实现。 (如果我猜对了)。

如果您真的想遵循这种方法,请查看此答案

现在,你的问题

  • 如果您想为元素属性提供“缓存”,那很好。 您可以创建一个 class 来为您保存元素,并且在每个FindElement()之前检查它是否已经存在。
  • 如果您还希望能够“单击”一个元素,那是不可能的。 如果您在按钮上“查找元素”,然后页面发生更改,并且您想从缓存中单击()它,那将不会发生。 页面变了。 抛出异常是有原因的。

我将假设您只想“缓存”有关元素的属性/信息,而不是实际与之交互。

然后,我们只需要创建一个“中间人”来处理每个元素的定位,但也会缓存我们找到的元素。 如果我们再次询问,class 将从 memory 将它们提供给我们,而不是“重新定位”它们。 让我们将它们作为扩展方法来做一些漂亮的事情:

public static class ElementLocator
{
    private static readonly Dictionary<By, IWebElement> _CachedElements;

    public static IWebElement FindElementFromCache(this IWebDriver driver, By by)
    {
        if (_CachedElements.ContainsKey(by))
            return _CachedElements.Single(e => e.Key == by).Value;

        return driver.FindElement(by);
    }

    public static ReadOnlyCollection<IWebElement> FindElementsFromCache(this IWebDriver driver, By by)
    {
        if (_CachedElements.ContainsKey(by))
        {
            List<IWebElement> foundCache = _CachedElements.Where(e => e.Key == by)
                                                          .Select(e => e.Value)
                                                          .ToList();

            return new ReadOnlyCollection<IWebElement>(foundCache);
        }

        return driver.FindElements(by);
    }

    static ElementLocator()
    {
        _CachedElements = new Dictionary<By, IWebElement>();
    }
}

然后,您可以简单地执行driver.FindElementFromCache(By.Id("someElement"));

但这可能不是完整的实现。 因为,在搜索多个元素时,可能添加了一个新元素。 一分钟前你得到了 4 个元素,现在添加了一个新的表格行,你有 5 个元素。 ElementLocator 将尝试查看缓存中是否有任何内容,将找到 4 个元素并将它们返回给您,而不搜索第 5 个元素。

IMO,创建缓存机制可能不是解决您问题的最佳方法。 它引入了(请原谅我的语言)你将面临的一大堆问题。

如果您可以向我们展示问题所在,我们可以找出可能不涉及缓存的问题。 我的意思是,不要说“我怎样才能更好地做这个缓存”或“我的缓存有问题”,但让我们看看为什么你需要一个缓存来开始元素。

祝你好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM