Можно ли создать статическое поле в базовом классе, но повлиять на создание в дочернем классе? - PullRequest
0 голосов
/ 14 июля 2009

Мне нужно создать базовый класс, как в следующем коде.

public class ResourceBase
{
    protected static IDictionary<string, XDocument> resources;

    protected static IDictionary<string, XDocument> Resources
    {
        get
        {
            if (resources == null)
            {
                // cache XDocument instance in resources variable seperate by culture name.
                // load resx file to XDocument
            }

            return resources;                
        }
    }

    protected static string GetString(string resourceKey)
    {
        return GetString(resourceKey, System.Threading.Thread.CurrentThread.CurrentUICulture.Name);
    }

    protected static string GetString(string resourceKey, string cultureName)
    {
        // get data from XDocument instance
        var result = (
                        from rs in Resources
                        let node = rs.Value.Root.Elements(XName.Get("data")).SingleOrDefault<XElement>(x => x.Attribute(XName.Get("name")).Value == resourceKey)
                        where
                                (rs.Key == DEFAULT_CULTUREKEY || cultureName == rs.Key) &&
                                node != null
                        orderby cultureName == rs.Key descending
                        select node.Element(XName.Get("value"))
                     ).FirstOrDefault<XElement>();

        return result.Value;
    }
}

Затем я создаю дочерний класс, как показано в следующем коде.

public class MainResource : ResourceBase
{
    public static string AppName
    {
        return GetString("AppName");
    }
}

public class OtherResource : ResourceBase
{
    public static string OtherName
    {
        return GetString("OtherName");
    }
}

У меня есть проблема из-за переменной ресурса в базовом классе. Все дочерние классы используют некоторую переменную Resource. Таким образом, они всегда используют один и тот же кэшированный экземпляр XDocument. У вас есть идея исправить мой исходный код?

PS. Я нашел некоторый атрибут, такой как ContextStaticAttribute, который указывает, что значение статического поля уникально для определенного контекста. Я думаю конкретный контекст должен быть нить разницы. Поэтому я не могу использовать его для решения этого вопроса.

Спасибо

Ответы [ 5 ]

3 голосов
/ 14 июля 2009

Это, кажется, требует реализации Singleton. Причина вашего базового класса заключается в том, чтобы поделиться логикой, правильно? Вместо того чтобы делать все статично, реализуйте шаблон Singleton, чтобы у каждого из ваших дочерних классов был свой экземпляр, и все они разделяли логику из вашего базового класса.

Это позволит им иметь независимое кэширование при совместном использовании логики поведения.

3 голосов
/ 14 июля 2009

Сделать базовый класс абстрактным и не предоставлять реализацию для Ресурсов. Затем производный класс может предоставить собственный ресурс методу базового класса GetString.

0 голосов
/ 15 июля 2009

2. Более простое решение для решения этой проблемы с использованием только расширения метода.

Файл ресурсов со строгой типизацией

[ResourceInfo("~/Views/Home", "Index")]
public class IndexView
{
    protected static IDictionary<string, XDocument> resources = new Dictionary<string, XDocument>();

    public static string Title
    {
        get
        {
            return resources.GetString("Title");
        }
    }
}

Файл помощника ресурса

public static class ResourceHelper
{
    const string RESOURCE_EXTENSION = "resx";
    const string DEFAULT_CULTUREKEY = "(default)";

    public static string GetString(this IDictionary<string, XDocument> resource, string resourceKey)
    {
        return resource.GetString(resourceKey, System.Threading.Thread.CurrentThread.CurrentUICulture.Name);
    }

    public static string GetString(this IDictionary<string, XDocument> resource, string resourceKey, string cultureName)
    {
        if (resource.Count == 0)
            resource.LoadResource();

        // retrieve data
    }

    public static void LoadResource(this IDictionary<string, XDocument> resource)
    {
        // logic to load resource
    }

Я проверил эту логику в том же тесте, что и # solution1. Но я нашел очень интересный результат. Он может извлечь более 120000 операций / сек . Итак, это мой окончательный ответ, потому что он простой, чистый и быстрый.

Спасибо

0 голосов
/ 15 июля 2009

1.Решение решения этой проблемы с использованием статической переменной ресурсов для кэширования всех ресурсов зависит от типа дочернего класса.

public class ResourceBase
{
    protected static IDictionary<Type, IDictionary<string, XDocument>> resources;
    protected static IDictionary<string, XDocument> Resources
    {
        get
        {
            if (resources == null)
            {
                // cache XDocument instance in resources variable seperate by type and culture name.
                // load resx file to XDocument
            }

            return resources;
        }
    }
}

Кстати, для этого решения каждый раз требуется дочерний класс Type с использованием следующего кода, когда я получаю значение ресурса. Кроме того, я протестировал это решение около 10 000 - 100 000 раундов, и оно может извлекать данные о 6000 операций / сек . Поэтому я не могу использовать это решение для реальных приложений, поскольку каждый веб-запрос должен извлекать более 50 операций.

public static Type GetCallerType(Type baseClass, int skipFrames)
{
    StackTrace trace = new StackTrace(skipFrames + 1, false);
    Type callerType = null;

    for (int i = 0; i < trace.FrameCount; ++i)
    {
        StackFrame frame = trace.GetFrame(i);
        Type type = frame.GetMethod().DeclaringType;

        if (type == baseClass || IsInheritFrom(type, baseClass))
        {
            callerType = type;
        }
        else
        {
            break;
        }
     }

     if (callerType != baseClass)
        return callerType;
     else
        return null;
}
0 голосов
/ 14 июля 2009

Похоже, вам нужно каждый раз кэшировать ваши дочерние классы. Когда вы кешируете XDocument, вам нужно предоставить ключ, который отличается от вашего дочернего класса. Вы можете добавить это в свой базовый класс

abstract string ResourceName { get; };
protected static IDictionary<string, XDocument> Resources
{
    get
    {
        if (resources == null)
        {
            //Cache the XDocument with a key based on ResourceName.
        }

        return resources;                
    }
}

И тогда ваш главный ресурс имеет

string ResourceName { get { return "AppName"; } }

public static string AppName
{
    return GetString(ResourceName);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...