Страницы

Поиск по вопросам

Показаны сообщения с ярлыком атрибуты. Показать все сообщения
Показаны сообщения с ярлыком атрибуты. Показать все сообщения

воскресенье, 8 марта 2020 г.

Можно ли обратится к элементу(элементам) через несколько указание нескольких атрибутов?

#html #css #атрибуты #css_selectors


Возможно ли обратится к элементу(элементам) через указание нескольких атрибутов?

например: [class*="col"][role="main"] или [class*="col", role="main"] или [class*="col"
role="main"]

Если возможно, то как корректно?
    


Ответы

Ответ 1



Попробуйте так:
first
second
third
Документация доступна на русском по ссылке. Документация доступна английском по ссылке.

четверг, 13 февраля 2020 г.

ThreadStatic атрибут, тонкости использования

#c_sharp #атрибуты


Для меня непонятен этот момент из документации:


  Для полей с атрибутом ThreadStatic начальные значения указывать не нужно, поскольку
такая инициализация происходит только один раз, при выполнении конструктора класса,
и затрагивает только один поток. Если не указать начальные значения, полю, относящемуся
к типу значения, будет присвоено значение по умолчанию, а полю, относящемуся к ссылочному
типу — значение null. 


и


  Следует учитывать, что любой код конструктора класса будет работать с первым потоком
в первом контексте, получающим доступ к полю. Поля во всех других потоках и во всех
других контекстах в пределах того же домена приложения будут инициализированы значением
null (Nothing в Visual Basic), если они имеют ссылочные типы, или значениями по умолчанию,
если они имеют типы значения. Поэтому не следует полагаться на инициализацию статических
полей потока конструкторами классов. Напротив, следует избегать инициализации статических
полей потока и предполагать, что они инициализированы значениями null (Nothing) или
значениями по умолчанию. 


Допустим у нас есть поле:

[ThreadStatic]
public static int Timeout = 50000;


При обращении к полю из первого потока поле отдаст значение 50000, а при обращении
из второго - отдаст 0? Я правильно понимаю?
    


Ответы

Ответ 1



Так и есть. При обращению в том потоке, где объект был создан, прочитается 50000, а в других — 0. Но полагаться на это не стоит: если объект используется в нескольких потоках, не всегда легко отследить, в каком же потоке он был реально создан (и это может быть источником тонких, редко проявляющихся ошибок). Кроме того, ваш код проиграет в читаемости: вы ведь пишете Timeout = 50000, и читатель вашего кода должен всё время держать в голове «... но только в том потоке, в котором этот объект был создан». Поэтому лучше, как и советует MSDN, вовсе не инициализировать объект. При этом его значение в начале будет равно default(int), то есть 0, во всех потоках. Обновление: конечно, инициализация пройдёт не в том потоке, где был создан объект (объектов ведь много), а в котором выполнился статический конструктор. То есть обычно это поток, в котором создаётся первый объект. Спасибо @MaLS за наводку. Заметьте, что существует более удобное решение, если вы пользуетесь .NET 4 или старше: класс ThreadLocal. Для него вы можете легко установить начальное значение в каждом из потоков: public static ThreadLocal Timeout = new ThreadLocal(() => 50000); Лямбда-функция будет испоьзована для вычисления начального значения в каждом из потоков. Она может, в принципе, в каждом потоке возвращать своё, отдельное значение.

Ответ 2



Если статическое поле класса с атрибутом ThreadStatic имеет начальное значение, то это значение будет присвоено полю только в том потоке, который вызывает статический конструктор класса, в остальных потоках данное поле будет иметь значение по умолчанию.

четверг, 9 января 2020 г.

Как еще можно задать default-значение переменной кроме try-except?

#python #python_3x #атрибуты


Объект obj - это инстанс какой-то джанго-модели. Допустим, у него есть поле prop,
которое по идее должно быть связано с другой моделью, но может также быть None. Моя
задача - записать в переменную var поле target второй связанной модели.

var = obj.prop.target


Если поле prop окажется равно None, то все сломается, так как у None нет поля target.
В этом случае я хочу записать в переменную var значение None. В принципе я могу это
сделать так

try:
    var = obj.prop.target
except AttributeError:
    var = None


Нет ли какого-нибудь другого способа это сделать, наподобие setdefault у  словарей? 
    


Ответы

Ответ 1



Воспользуйтесь встроенной функцией getattr(object, name[, default]): var = getattr(obj.prop, "target", None) Выдержка из документации: getattr(object, name[, default]) Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, 'foobar') is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.

понедельник, 30 декабря 2019 г.

Узнать, есть ли атрибут у вызывающего метода?

#c_sharp #attribute #атрибуты


Есть тестовое консольное приложение.

internal class Program
{
    [MyTest("TestDescription")]
    static void Main(string[] args)
    {
        TestSchmest ta = new TestSchmest();
        ta.GetSomeThingMethod();

        Console.ReadKey();
    }
}

internal class TestSchmest
{
    public void GetSomeThingMethod([CallerMemberName] string methodName = "")
    {
        Console.WriteLine("\t - In hell we die!!!");
        WhoCalledMe();
        Console.WriteLine();
        Console.WriteLine("Method \"GetSomeThingMethod\" was called by {0}.", methodName);

        // methodName.GetAttribute ???
    }

    private void WhoCalledMe([CallerMemberName] string methodName = "")
    {
        Console.WriteLine("\t - For what?!");
        Console.WriteLine();
        Console.WriteLine("Method \"WhoCalledMe\" was called by {0}.", methodName);

        // methodName.GetAttribute ???
    }
}

public class MyTestAttribute : Attribute
{
    protected string Description;

    public MyTestAttribute(string description)
    {
        Description = description;
    }
}


Сначала вызывается метод GetSomeThingMethod класса TestSchmest, который в свою очередь
вызывает метод WhoCalledMe. Можно ли как-то из методов класса TestSchmest узнать, указан
ли атрибут у вызывающего их метода или нет.

Т.е. ta.GetSomeThingMethod() должен показать, что атрибут есть, а WhoCalledMe() что
его нет.

Название класса, в котором вызываются методы (в данном случае Program) может быть
неизвестно.
    


Ответы

Ответ 1



С помощью класса StackTrace можно получить предыдущий кадр стека, относящийся к вызвавшему методу. Атрибут CallerMemberName при этом не требуется. public void GetSomeThingMethod() { string methodName = ""; MyTestAttribute attribute = null; var st = new StackTrace(); if (st.FrameCount > 1) { var prevFrame = st.GetFrame(1); // получаем кадр стека для вызвавшего метода var caller = prevFrame.GetMethod(); // получаем сам вызвавший метод methodName = caller.Name; var attributes = caller.GetCustomAttributes(typeof(MyTestAttribute), false); if (attributes.Length > 0) attribute = (MyTestAttribute)attributes[0]; } Console.WriteLine("\t - In hell we die!!!"); WhoCalledMe(); Console.WriteLine(); Console.WriteLine("Method \"GetSomeThingMethod\" was called by {0}.", methodName); if (attribute != null) Console.WriteLine("Attribute is present."); } Результат: Method "GetSomeThingMethod" was called by Main. Attribute is present.

Ответ 2



Можно получить MethodInfo через класс StackTrace. Учтите, что это достаточно медленный способ, к тому же вам придется отключить inlining, чтобы JIT не вздумал встроить вызываемый / вызывающий метод в тело другого метода - иначе вы просто не увидите метод в stack trace: using System; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; namespace ConsoleApplication58 { class Program { static void Main(string[] args) { AttributedMethod(); NonAttributedMethod(); } [MyTest("Some Description")] [MethodImpl(MethodImplOptions.NoInlining)] static void AttributedMethod() { CallerDetectionSample(); } [MethodImpl(MethodImplOptions.NoInlining)] static void NonAttributedMethod() { CallerDetectionSample(); } [MethodImpl(MethodImplOptions.NoInlining)] public static void CallerDetectionSample() { // Get call stack StackTrace stackTrace = new StackTrace(); // Get calling method name var attibutes = stackTrace.GetFrame(1).GetMethod().GetCustomAttributes(typeof(MyTestAttribute), true); var description = attibutes.Cast() .Select(a => a.Description) .FirstOrDefault() ?? "no attribute!"; Console.WriteLine(description); } } public class MyTestAttribute : Attribute { public string Description { get; set; } public MyTestAttribute(string description) { Description = description; } } }

вторник, 10 декабря 2019 г.

Деньги в юнит-тестах: использование decimal в аттрибутах

#c_sharp #юнит_тесты #атрибуты #nunit


Есть несколько однотипных юнит-тестов nUnit, в которых проверяется парсинг строки
в decimal (именно этот тип рекомендуется в c# для денежных единиц):

[Test]
public void Test3()
{
    // Arrange
    var input = "1,234.56";

    // Act
    var result = MoneyParser.Parse(input);

    // Assert
    Assert.AreEqual(1234.56m, result);
}


Ну и я соответственно захотел всё это элегантно упаковать в один метод навесив атрибут
TestCase:

[TestCase("1234", 1234m)]
[TestCase("1234.56", 1234.56m)]
[TestCase("1234,56", 1234.56m)]
[TestCase("1 234.56", 1234.56m)]
[TestCase("1 234,56", 1234.56m)]
[TestCase("1,234.56", 1234.56m)]
public void Test(string input, decimal expected)
{
    var result = MoneyParser.Parse(input);

    Assert.AreEqual(expected, result);
}


Однако в атрибутах можно использовать только примитивные типы, а код с decimal даже
не компилируется — выдаёт ошибку:


  Error CS0182 An attribute argument must be a constant expression,
  typeof expression or array creation expression of an attribute
  parameter type


Как можно обойти это препятствие и написать читаемый тест? На ум приходит только
вариант задавать на входе expected строкой, преобразовывать внутри теста - и это не
нравится ни тем, что легко поломать текст невалидными данными (нет типобезопасностм),
ни тем, что придётся загромождать код лишними преобразованиями. 
    


Ответы

Ответ 1



Поскольку в C# тип double может неявно преобразовываться в тип decimal, можно просто убрать постфикс m для всех decimal-значений в атрибуте TestCase. Потерь по точности в данном случае не будет (это можно легко проверить, если нужно). В конечном итоге тест будет выглядеть примерно так: [TestFixture] public class MoneyParserTests { [TestCase("1234", 1234)] [TestCase("1234.56", 1234.56)] [TestCase("1234,56", 1234.56)] [TestCase("1 234.56", 1234.56)] [TestCase("1 234,56", 1234.56)] [TestCase("1,234.56", 1234.56)] public void Test(string input, decimal expected) { var result = MoneyParser.Parse(input); Assert.AreEqual(expected, result); } } Единственный минус: глядя на эти тесткейсы не скажешь, что метод принимает именно decimal параметры. В других случаях Unit-тест будет обрастать лишними проверками, явными преобразованиями и т.д.

Ответ 2



Можно попробовать передать тесты не через атрибуты, с помощью TestCaseSource. Получится страшненько, но сработает: private static readonly Tuple[] cases = new[] { Tuple.Create("1234", 1234m), Tuple.Create("1234.56", 1234.56m), Tuple.Create("1234,56", 1234.56m), Tuple.Create("1 234.56", 1234.56m), Tuple.Create("1 234,56", 1234.56m), Tuple.Create("1,234.56", 1234.56m) }; private static object[] TestCases() { return cases.Select(t => new object[] { t.Item1, t.Item2 }).ToArray(); } [TestCaseSource(nameof(TestCases))] public void Test(string input, decimal expected) { var result = MoneyParser.Parse(input); Assert.AreEqual(expected, result); } Преимущество: до определенной степени сохранена типобезопасность при изменении тестов. Недостатки: читаемость упала; из-за сигнатуры object[] сломать код достаточно легко; появился код для преобразования данных.

понедельник, 15 июля 2019 г.

Допускается ли одновременно атрибут charset и name в элементе meta?

В спецификации html5 в описании элемента meta говорится следующее:
Exactly one of the name, http-equiv, and charset, attributes must be specified.
Примерный перевод: Только один из атрибутов может быть использован: name, http-equiv, или charset. Правильно ли я понимаю, что не могу писать так?

Т.е. либо я пишу в одном html документе

либо

Допустим если я хочу указать автора Sergey т.е. типа так

то как мне, чтобы соблюсти стандарт html5 указать еще и кодировку utf-8, ведь по стандарту нельзя одновременно использовать meta name и utf-8? Или может я неправильно перевел стандарт?


Ответ

Правильно ли я понимаю, что не могу писать так?

Правильно. Так как элемент meta позволяет задать только одну из трёх характеристик (name, charset, http-equiv) документа за раз
В данном же случае нужно написать так:

Так как количество элементов meta не ограничивается одним его экземпляром, за исключением , поскольку она должна задаваться один раз.

воскресенье, 26 мая 2019 г.

Можно ли обратится к элементу(элементам) через несколько указание нескольких атрибутов?

Возможно ли обратится к элементу(элементам) через указание нескольких атрибутов?
например: [class*="col"][role="main"] или [class*="col", role="main"] или [class*="col" role="main"]
Если возможно, то как корректно?


Ответ

Попробуйте так:

first
second
third


Документация доступна на русском по ссылке
Документация доступна английском по ссылке

четверг, 13 декабря 2018 г.

Узнать, есть ли атрибут у вызывающего метода?

Есть тестовое консольное приложение.
internal class Program { [MyTest("TestDescription")] static void Main(string[] args) { TestSchmest ta = new TestSchmest(); ta.GetSomeThingMethod();
Console.ReadKey(); } }
internal class TestSchmest { public void GetSomeThingMethod([CallerMemberName] string methodName = "") { Console.WriteLine("\t - In hell we die!!!"); WhoCalledMe(); Console.WriteLine(); Console.WriteLine("Method \"GetSomeThingMethod\" was called by {0}.", methodName);
// methodName.GetAttribute ??? }
private void WhoCalledMe([CallerMemberName] string methodName = "") { Console.WriteLine("\t - For what?!"); Console.WriteLine(); Console.WriteLine("Method \"WhoCalledMe\" was called by {0}.", methodName);
// methodName.GetAttribute ??? } }
public class MyTestAttribute : Attribute { protected string Description;
public MyTestAttribute(string description) { Description = description; } }
Сначала вызывается метод GetSomeThingMethod класса TestSchmest, который в свою очередь вызывает метод WhoCalledMe. Можно ли как-то из методов класса TestSchmest узнать, указан ли атрибут у вызывающего их метода или нет.
Т.е. ta.GetSomeThingMethod() должен показать, что атрибут есть, а WhoCalledMe() что его нет.
Название класса, в котором вызываются методы (в данном случае Program) может быть неизвестно.


Ответ

С помощью класса StackTrace можно получить предыдущий кадр стека, относящийся к вызвавшему методу. Атрибут CallerMemberName при этом не требуется.
public void GetSomeThingMethod() { string methodName = ""; MyTestAttribute attribute = null;
var st = new StackTrace(); if (st.FrameCount > 1) { var prevFrame = st.GetFrame(1); // получаем кадр стека для вызвавшего метода var caller = prevFrame.GetMethod(); // получаем сам вызвавший метод methodName = caller.Name;
var attributes = caller.GetCustomAttributes(typeof(MyTestAttribute), false); if (attributes.Length > 0) attribute = (MyTestAttribute)attributes[0]; }
Console.WriteLine("\t - In hell we die!!!"); WhoCalledMe(); Console.WriteLine(); Console.WriteLine("Method \"GetSomeThingMethod\" was called by {0}.", methodName);
if (attribute != null) Console.WriteLine("Attribute is present."); }
Результат:
Method "GetSomeThingMethod" was called by Main. Attribute is present.