Обновить

Комментарии 20

У меня небольшой вопрос к автору: Вы знаете, что фраза «окончательное решение вопроса» несёт в себе некоторый культурный подтекст, и обычно используется только в связи с этим контекстом?

я пишу это потому, что кое кого за такую формулировку уже заминусовали…

буквоедство - болезнь мозга, которой часто подвержены программисты в силу профессиональной деформации с синтаксис-контролем.

я хоть и программист, но много общался с женщинами, это хорошее противоядие. Рекомендую.

Эта "пластинка" про буквоедство - очень удобное оправдание неспособности корректно формулировать мысли.
Значит, корректировка типовых шаблонов у вас слетит при обновлении. А замена типовых шаблонов на ваш Основной не слетит.

иногда буквоедство это признак граммар-наци.

я предлагаю метод, а как вы будете его использовать - совместно с типовыми ролями или вместо типовых ролей, дело хозяйское.

главное, у программистов по RLS на чтение теперь появился выбор. Раньше его, все 10 лет существования RLS не было. В этом ценность.

Я предлагаю на чтение делать одну роль.

На изменения, конечно, контроль в модулях.

Так будет законченная и логичная система прав в отличии от типовой галочной стыдобы в 1С.

Влияет ли на производительность шаблон с большим количеством #Если?

нет, все компилируется на этапе сохранения метаданных (компиляции), т.е. это не run-time вычисления.

Скорее это аналог макросов в Си, где просто подставляются параметры в результирующий код.

Кстати, так не хватает макросов в Cи Шарп...

C# содержит директивы препроцессора. Они не настолько развиты как в Си, но с другой стороны, что они там и не нужны

я про макросы #Define, это мощная штука.

В C# есть кодогенерация https://habr.com/en/articles/906778/ и сорсгенерация. Если не достаточно дженериков и экстеншенов, то не слабее штука.

ну вот пример.

В зависимости от типа устройства может быть возвращена структура A1, A2 или A3.

Мне надо с результатом вызвать процедуру Work и Bench.

Например:

R = GetValueFromDevice();

If R.code = 1 {

V = R.value as A1;

Work_A1(v);

Bench_A1(v);

}

elseIf R.code = 2 {

V = R.value as A2;

Work_A2(v);

Bench_A2(v);

}

elseIf R.code = 3 {

V = R.value as A3;

Work_A3(v);

Bench_A3(v);

}

Конечно, можно городить обертки над структурами, но это не так красиво, как макросы.

switch (code)
{
    case 1: Test<A1>(value, Work_A1,Bench_A1); break;
    case 2: Test<A1>(value, Work_A2, Bench_A2); break;
    case 3: Test<A3>(value, Work_A3, Bench_A3); break;
}

static void Test<T>(object a, Action<T> work, Action<T> bench)
{
    T t = (T)a;
    work(t);
    bench(t);
}

Выглядит неплохо. Применю на практике по оказии, спасибо.

Если тип устройства, то, конечно, надо смотреть, что за структура -- может надо довести до CLR. Но пусть все просто будет.

  1. Путь интерфейсов (он же про дженерики)

    // можно и без него, но просто понимать что что-то есть внутри
    abstract class BaseA { 
      public BaseA(string value) {
        Value = value; // какое-то создание
      }
      public string Value {get; init;}
    }
    
    // можно методы объеденить
    interface IA {
      void Work();
      void Bench();
    }
    
    // эти классы по ходу у тебя уже есть
    // им только добавить интерфейсы
    class A1: BaseA, IA {
      public A1(string value): base(value) {}
      public void Work() {
        // логика для Work_A1(this.Value)
      }
      public void Bench() {
      	// логика для и Bench_A1(this.Value)
      }
    }
    class A2: BaseA, IA {
      public A2(string value): base(value) {}
      public void Work() {
        // логика для Work_A1(this.Value)
      }
      public void Bench() {
      	// логика для и Bench_A2(this.Value)
      }
    }
    class A3: BaseA, IA {
      public A3(string value): base(value) {}
      public void Work() {
        // логика для Work_A3(this.Value)
      }
      public void Bench() {
      	// логика для и Bench_A3(this.Value)
      }
    }
    
    // конечный код
    var R = GetValueFromDevice();
    var concrete_A = R.value () switch {
        1 => new A1(R.value),
        2 => new A2(R.value),
        3 => new A3(R.value),
    	_ => throw new Exception("неизвестное устройство")
    };
    concrete_A.Work();
    concrete_A.Bench();
    
    // и даже можно будет так
    var deviceList = new List<IA>
      {
        new A1("a1"), new A2("a2"), new A2("a2-2"))
      };
    foreach (var device in deviceList)
    {
      device.Work();
      device.Bench();
    }
  2. Путь экстеншенов

    abstract class BaseA { 
      public BaseA(string value) {
        Value = value; // какое-то создание
      }
      public string Value {get; init;}
    }
    
    class A1: BaseA {
      public A1(string value): base(value) {}
    }
    class A2: BaseA {
      public A2(string value): base(value) {}
    }
    class A3: BaseA {
      public A3(string value): base(value) {}
    }
    
    // если не интерфейсы, то вот
    // и для краткости объединяю методы целевые
    static class AExtensions {
    	static void WorkAndBench(this A1 a) {
    		// Work_A1(a.Value);
    		// Bench_A1(a.Value);
    	}
    
    	static void WorkAndBench(this A2 a) {
    		// Work_A2(a.Value);
    		// Bench_A2(a.Value);
    	}
    
    	static void WorkAndBench(this A3 a) {
    		// Work_A3(a.Value);
    		// Bench_A3(a.Value);
    	}
    }
    
    // конечный код
    var R = GetValueFromDevice();
    var concrete_A = R.value () switch {
        1 => new A1(R.value),
        2 => new A2(R.value),
        3 => new A3(R.value),
    	_ => throw new Exception("неизвестное устройство")
    };
    concrete_A.WorkAndBench();
    
    // с колекцией тоже прокатит
  3. А так -- патерн chain of responsibility или какой-то другой пайплайн, если девайс один.

Но если вариантов десятки, то генерацию подключать.

А вообще кажется классы не нужны и можно так

var dict = new Dictionary<int, Action<string>> {
 {1, value => {Work_A1(value); Bench_A1(value);)},
 {2, value => {Work_A2(value); Bench_A2(value);)},
 {3, value => {Work_A3(value); Bench_A3(value);)}
};

R = GetValueFromDevice();
dict[R](R.value);
  1. В производительном режиме типовых 1С (библиотека БСП) не требуется менять шаблоны RLS. Делается это иначе, например тут описано https://infostart.ru/1c/articles/1656341/

  2. Вам придется этот шаблон скопировать во все роли, использующие RLS. Главное ничего не пропустить. Кроме того, т.к. шаблон хранить ВСЕ правила - это путь к коллизиям файлов при групповой разработке. Во всех ролях.

  3. Ваши примеры не покрывают размещения пользователя в разных областях ограничений. Например, в типовых решениях пользователя можно поместить в группу доступа с ограничением склад "Север", а также в группу доступа с ограничением клиенты менеджера "Вася". В итоге он будет видеть документы по складу "Север" ИЛИ по менеджеру "Вася".

  1. при чем тут производительный режим, у которого своя "тележка недостатков"

  2. нет. мне достаточно иметь только одну роль с RLS, если одна роль расово неприемлема и хочется прям разделения по ролям, то во всех ролях, где доступен просмотр, пишите Где ЛОЖЬ, чтобы они не давали право на просмотр.

  3. В статье этого нет, но я приводил вам пример тут https://infostart.ru/1c/articles/2622960/ (в сообщении номер 4), как это решается в "моём случае". Ничего не мешает использовать справочник групп доступа и в моем решении. Методу это не противоречит.

  1. Какие недостатки типового производительного режима по сравнению с данным решением?

  2. Роль ГДЕ ЛОЖЬ и Роль где отключено право чтения это совершенно разное поведение системы.

  3. Вы меня с кем-то путаете.

  1. Производительный режим - https://infostart.ru/1c/articles/1656341/, недостатки:
    - нужно рассчитывать по-объектно и хранить эти доступы.
    - тяжеловесность решения
    - сложность добавления своих отборов, впрочем как и все, что взаимодействует с монструозной БСП.
    Помню в Документообороте 2.0 права доступа по-объектно пересчитывались сутками на больших объемах.
    Да, это очевидная попытка снизить сложность настройки RLS на чтение, которая была, пока я не предложил этот метод. Этот метод побивает производительный режим.

  2. в чем разница? роль с RLS одна, она как раз управляет доступностью объектов на просмотр. Мне достаточно одной роли, это полностью закрывает проблему с видимостью через RLS. Это удобно.

  3. ну если это не вы писали, то почитайте, там пользователь задавал такой же вопрос как вы и я ему подробно ответил.

  1. В производительном режиме делается иначе, то есть заведомо написали ложь. По поводу "тяжеловесности" и "монструозности" - это все слова, надо подкреплять фактами. Покажите свой продукт, сделайте сравнения

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

  3. Исходя из написанного - "переобуваемся" на ходу, довешиваем новые данные и... вот уже тоже самое, только свой велосипед, родной )))

-- В производительном режиме делается иначе, то есть заведомо написали ложь.

что не так, напишите своими словами.

-- По поводу "тяжеловесности" и "монструозности" - это все слова, надо подкреплять фактами. Покажите свой продукт, сделайте сравнения

несомненно, но перспективы метода уже неплохи. Я давно искал такой. Жаль, раньше не знал, думаю и сейчас кто-то в поисках, им пригодится.

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

приведите пример, не понимаю о чем вы.

-- Исходя из написанного - "переобуваемся" на ходу, довешиваем новые данные и... вот уже тоже самое, только свой велосипед, родной )))

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации