Опыты с автоматическим переводом кода C# в 1С-код через Roslyn

26.12.14

Разработка - Языки и среды

Появилась идея посмотреть, как будет выглядеть объектно-ориентированный подход в 1С, язык которой очень ограничен в средствах и не предусматривает определение классов. Программа по автоматическому переводу определений классов C# в другой язык позволила бы менять генерируемый код по мере появления новых идей. Поиски средств реализации привели к проекту Roslyn - открытому компилятору C#.

Появилась идея посмотреть, как будет выглядеть объектно-ориентированный подход в 1С, язык которой очень ограничен в средствах и не предусматривает определение классов. Программа по автоматическому переводу определений классов C# в другой язык позволила бы менять генерируемый код по мере появления новых идей. Поиски средств реализации привели к проекту Roslyn – открытому компилятору C#.

Roslyn – это открытая платформа компиляции C# и Visual Basic. Roslyn выполняет два основных действия: строит синтаксическое дерево (парсинг) и компилирует синтаксическое дерево. Дополнительно позволяет анализировать исходный код, рекурсивно обходить его, работать с проектами Visual Studio, выполнять код на лету.

Обратите внимание, что на данный момент Roslyn в стадии Бета. Исходя из этого, со временем в компиляторе может что-то поменяться.

Roslyn – открытый компилятор C#



Подключить Roslyn в проект можно через Nuget:

Install-Package Microsoft.CodeAnalysis –Pre 


Для удобства в коде лучше сразу подключить три пространства имен

using Microsoft.CodeAnalysis.CSharp; 
using Microsoft.CodeAnalysis.CSharp.Syntax; 
using Microsoft.CodeAnalysis; 


Получить синтаксическое дерево кода из строки (или файла) можно так:

SyntaxTree tree = CSharpSyntaxTree.ParseText(codeString); 


Синтаксическое дерево представляет из себя иерархию объектов, наследованных от SyntaxNode. Объекты созданы на все случаи жизни. Примеры: ClassDeclarationSyntax — определение класса, NamespaceDeclarationSyntax – определение пространства имен, PropertyDeclarationSyntax – определение свойства, AccessorDeclarationSyntax – определение метода доступа к свойству (get/set), BlockSyntax – содержимое блока (между фигурными скобками), ExpressionStatementSyntax – выражение и т.д.

Если есть задача рекурсивно пройти все элементы дерева, можно создать свой класс Walker и наследовать его от CSharpSyntaxWalker. Базовый класс позволяет переопределять общий метод Visit(SyntaxNode node) или большое множество специализированных, вида: void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node), void VisitClassDeclaration(ClassDeclarationSyntax node), void VisitConstructorDeclaration(ConstructorDeclarationSyntax node) и т.д. Не забывайте вызвать в каждом переопределенном методе базовый метод, чтобы не останавливать рекурсии.

Вызов рекурсивного обхода можно запустить следующим образом:

var walker = new Walker(); walker.Visit(tree.GetRoot()); 


В синтаксическом дереве нет информации о типах. Информация об используемых типах появляется после вызова:

var compilation = CSharpCompilation.Create("1ccode").WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)).AddReferences(new MetadataFileReference(typeof(object).Assembly.Location)).AddSyntaxTrees(tree); 
var Model = compilation.GetSemanticModel(tree); 


После этого вызова можно получать информацию об используемых типах, вызывая, например для класса

var classSymbol = Model.GetDeclaredSymbol(classDeclarationSyntax); 


Теперь, имея информацию, о типе, можно узнать какой класс унаследовал данный тип:

var type = type.BaseType; 


Или получить все члены типа через type.GetMembers()

Автоматический перевод кода C# в код 1С



Код не претендует на полноту и правильность, так как имеет цель получить общее представление об ООП-подходе в 1С.

Для перевода C#-кода в код 1С был создан класс Walker, наследованный от CSharpSyntaxWalker. Walker перебирает все определения и строит на выходе 1С-код.

Класс производит следующие преобразования.

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

Понятия класс в 1С нет, поэтому определение класса в методе VisitClassDeclaration пропускается. Имя класса будет присутствовать в названии каждой функции и процедуры 1С, чтобы обозначить принадлежность к одному типу. Присутствующие в базовых классах методы, но отсутствующие в текущем классе через DeclareBaseClassMethodsToImplement и DeclareBaseClassPropertiesToImplement определяются с вызовом «базовых» функций/процедур 1С.

Конструкторы в VisitConstructorDeclaration переводятся в определения функций 1С с именем класса, первым параметром _this и списком параметров. Если нет вызова другого конструктора этого класса, происходит инициализация всех полей класса в структуре. Определяется вызов других конструкторов.

Определение свойств в VisitPropertyDeclaration пропускаются. Важны определения их методов доступа.

Методы доступа свойств в VisitAccessorDeclaration переводятся в определения с именами <название класса>_Получить_<имя свойства> и <название класса>_Установить_<имя свойства>. Если они авто-реализованные (auto-implemented), то генерируется код доступа к переменной _this._private_<название класса>_<имя свойства>.

Для методов в VisitMethodDeclaration генерируются определения 1С-процедур.

Выражения и «возвраты» в VisitExpressionStatement и VisitReturnStatement комментируются через // и вставляются в текст как есть.

Исходный код Walker.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis;
namespace Roslyn
{
    public class Walker : CSharpSyntaxWalker
    {
        SyntaxTree Tree { get; set; }
        CSharpCompilation Compilation { get; set; }
        SemanticModel Model { get; set; }
        TextWriter Writer { get; set; }
        public Walker(TextWriter writer, SyntaxTree tree, CSharpCompilation compilation) : base()
        {
            Writer = writer;
            Tree = tree;
            Compilation = compilation;
            Model = Compilation.GetSemanticModel(tree);
        }
        Dictionary<classdeclarationsyntax, fielddeclarationsyntax[]> _classFields = new Dictionary<classdeclarationsyntax, fielddeclarationsyntax[]>();
        NamespaceDeclarationSyntax _currentNamespace;
        ClassDeclarationSyntax _currentClass;
        PropertyDeclarationSyntax _currentProperty;
        private int Tabs = 0;
        public override void Visit(SyntaxNode node)
        {
            //Tabs++;
            //var indents = new String('\t', Tabs);
            //Writer.WriteLine(indents + node.GetType().Name + "/" + node.CSharpKind());
            base.Visit(node);
            //Tabs--;
        }
        public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
        {
            _currentNamespace = node;
            Writer.WriteLine("Модуль " + node.Name.ToString().Replace(".", "_"));
            base.VisitNamespaceDeclaration(node);
        }
        public override void VisitClassDeclaration(ClassDeclarationSyntax node)
        {
            _currentClass = node;
            var fields = node.ChildNodes().OfType<fielddeclarationsyntax>().ToArray();
            _classFields[node] = fields;
            Writer.WriteLine();
            Writer.WriteLine(string.Format("//Класс {0}", node.Identifier));
            base.VisitClassDeclaration(node);
            DeclareBaseClassPropertiesToImplement(node);
            DeclareBaseClassMethodsToImplement(node);
        }
        void DeclareBaseClassMethodsToImplement(ClassDeclarationSyntax classNode)
        {
            var classSymbol = Model.GetDeclaredSymbol(classNode);
            List<string> processedMembers = new List<string>();
            var type = classSymbol;
            while (type != null)
            {
                foreach(var member in type.GetMembers())
                {
                    var declarators = member.DeclaringSyntaxReferences;
                    if (declarators == null || declarators.Length == 0)
                        continue;
                    if (declarators.Length != 1)
                        throw new NotImplementedException();
                    var memberNode = declarators[0].GetSyntax() as MethodDeclarationSyntax;
                    if (memberNode == null)
                        continue;
                    if (processedMembers.Any(m=>m == member.Name))
                        continue;
                    processedMembers.Add(member.Name);
                    if (type == classSymbol)
                        //Skip original class members. Declare only base classes
                        continue;
                    Writer.WriteLine();
                    Writer.WriteLine(string.Format("Процедура {0}_{1}(_this)", _currentClass.Identifier, memberNode.Identifier));
                    Writer.WriteLine(string.Format("    {0}_{1}(_this);", type.Name, member.Name));
                    Writer.WriteLine(string.Format("КонецПроцедуры;"));
                }
                type = type.BaseType;
            }
        }
        void DeclareBaseClassPropertiesToImplement(ClassDeclarationSyntax classNode)
        {
            var classSymbol = Model.GetDeclaredSymbol(classNode);
            List<string> processedMembers = new List<string>();
            var type = classSymbol;
            while (type != null)
            {
                foreach(var member in type.GetMembers())
                {
                    var declarators = member.DeclaringSyntaxReferences;
                    if (declarators == null || declarators.Length == 0)
                        continue;
                    if (declarators.Length != 1)
                        throw new NotImplementedException();
                    var memberNode = declarators[0].GetSyntax() as PropertyDeclarationSyntax;
                    if (memberNode == null)
                        continue;
                    if (processedMembers.Any(m => m == memberNode.Identifier.ToString()))
                        continue;
                    processedMembers.Add(memberNode.Identifier.ToString());
                    if (type == classSymbol)
                        //Skip original class members. Declare only base classes
                        continue;
                    Writer.WriteLine();
                    Writer.WriteLine(string.Format("Функция {0}_Получить_{1}(_this)", _currentClass.Identifier, memberNode.Identifier));
                    Writer.WriteLine(string.Format("    Возврат {0}_Получить_{1}(_this);", type.Name, member.Name));
                    Writer.WriteLine(string.Format("КонецФункции;"));
                    Writer.WriteLine();
                    Writer.WriteLine(string.Format("Процедура {0}_Установить_{1}(_this, value)", _currentClass.Identifier, memberNode.Identifier));
                    Writer.WriteLine(string.Format("    {0}_Установить_{1}(_this);", type.Name, member.Name));
                    Writer.WriteLine(string.Format("КонецПроцедуры;"));
                }
                type = type.BaseType;
            }
        }
        public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax node)
        {
            Writer.WriteLine();
            var symbol = Model.GetDeclaredSymbol(node);
            List<string> parameters = new List<string>();
            parameters.Add("_this");
            parameters.AddRange(node.ParameterList.Parameters.Select(m => m.Identifier.ToString()).ToArray());
            Writer.WriteLine(string.Format("Функция {0}({1}){2}", node.Identifier, String.Join(", ", parameters), " Экспорт"));
            Writer.WriteLine();
            Tabs++;
            var indents = new String('\t', Tabs);
            //Initialize members first if no this constructor initializer (:this()) call
            if (!node.DescendantNodes().OfType<constructorinitializersyntax>().Any(m=>m.CSharpKind() == SyntaxKind.ThisConstructorInitializer) && _classFields.ContainsKey(_currentClass))
            {
                Writer.WriteLine(indents + String.Format("//Инициализация полей"));
                //Writer.WriteLine(String.Format("_this = Новый Структура();"));
                foreach (var field in _classFields[_currentClass])
                {
                    Writer.WriteLine(String.Format(indents + "_this.Вставить(\"{0}\", {1})", field.Declaration.Variables[0].Identifier, field.Declaration.Variables[0].Initializer.Value));
                }
            }
            if (node.Initializer != null)
            {
                List<string> arguments = new List<string>();
                arguments.Add("_this");
                arguments.AddRange(node.Initializer.ArgumentList.Arguments.Select(m => m.Expression.ToString()).ToArray());
                if (node.Initializer.ThisOrBaseKeyword.CSharpKind() == SyntaxKind.BaseKeyword)
                {
                    Writer.WriteLine(indents + String.Format("//Вызов конструктора базового класса"));
                    Writer.WriteLine(indents + String.Format("{0}({1});", _currentClass.BaseList.Types[0], String.Join(", ", arguments)));
                }
                else if (node.Initializer.CSharpKind() == SyntaxKind.ThisConstructorInitializer)
                {
                    Writer.WriteLine(indents + String.Format("//Вызов другого конструктора"));
                    Writer.WriteLine(indents + String.Format("{0}({1});", _currentClass.Identifier, String.Join(", ", arguments)));
                }
            }
            Writer.WriteLine(String.Format(indents + "_this.Вставить(\"__type\", \"{0}.{1}\")", symbol.ContainingNamespace.Name, symbol.ContainingType.Name));
            base.VisitConstructorDeclaration(node);
            Tabs--;
            Writer.WriteLine(indents + string.Format("Возврат _this;"));
            Writer.WriteLine(string.Format("КонецФункции; //{0}({1}){2}", node.Identifier, String.Join(", ", parameters), " Экспорт"));
        }
        public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node)
        {
            _currentProperty = node;
            var symbol = Model.GetDeclaredSymbol(node);
            base.VisitPropertyDeclaration(node);
        }
        public override void VisitAccessorDeclaration(AccessorDeclarationSyntax node)
        {
            Writer.WriteLine();
            if (node.CSharpKind() == SyntaxKind.GetAccessorDeclaration)
            {
                Writer.WriteLine(string.Format("Функция {0}_Получить_{1}(_this)", _currentClass.Identifier, _currentProperty.Identifier));
            }
            else if (node.CSharpKind() == SyntaxKind.SetAccessorDeclaration)
            {
                Writer.WriteLine(string.Format("Процедура {0}_Установить_{1}(_this, value)", _currentClass.Identifier, _currentProperty.Identifier));
            }
            Tabs++;
            if (node.Body == null)
            {
                //auto implemented
                var indents = new String('\t', Tabs);
                if (node.CSharpKind() == SyntaxKind.GetAccessorDeclaration)
                {
                    Writer.WriteLine(indents + string.Format("Возврат _this._private_{0}_{1};", _currentClass.Identifier, _currentProperty.Identifier));
                }
                else if (node.CSharpKind() == SyntaxKind.SetAccessorDeclaration)
                {
                    Writer.WriteLine(indents + string.Format("_this._private_{0}_{1} = value;", _currentClass.Identifier, _currentProperty.Identifier));
                }
            }
            base.VisitAccessorDeclaration(node);
            Tabs--;
            if (node.CSharpKind() == SyntaxKind.GetAccessorDeclaration)
            {
                Writer.WriteLine(string.Format("КонецФункции;"));
            }
            else if (node.CSharpKind() == SyntaxKind.SetAccessorDeclaration)
            {
                Writer.WriteLine(string.Format("КонецПроцедуры;"));
            }
        }
        public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
        {
            Writer.WriteLine();
            Writer.WriteLine(string.Format("Процедура {0}_{1}(_this)", _currentClass.Identifier, node.Identifier));
            Tabs++;
            base.VisitMethodDeclaration(node);
            Tabs--;
            Writer.WriteLine(string.Format("КонецПроцедуры;"));
        }
        public override void VisitExpressionStatement(ExpressionStatementSyntax node)
        {
            var indents = new String('\t', Tabs);
            Writer.WriteLine(("\r\n" + node.ToString()).Replace("\r\n", "\r\n" + indents + "//"));
            base.VisitExpressionStatement(node);
        }
        public override void VisitReturnStatement(ReturnStatementSyntax node)
        {
            var indents = new String('\t', Tabs);
            Writer.WriteLine(("\r\n" + node.ToString()).Replace("\r\n", "\r\n" + indents + "//"));
            base.VisitReturnStatement(node);
        }
        //public override void VisitBlock(BlockSyntax node)
        //{
        //    Writer.WriteLine(node.ToString());
        //    base.VisitBlock(node);
        //}
    }
}            
 

 

Результат работы



В итоге код

Исходный код на C#

          namespace ПространствоИмен1.ПИ2
{
    public class А
    {
        public А()
        {
            Свойство1 = "Конструктор А";
        }
        private int _поле1 = 10;        
        public int Поле1 {get {return _поле1;} set {_поле1 = value;}}        
        public string Свойство1 {get; set;}
        public void Метод1()
        {
            Свойство1 = "Метод1";
        }
    }
    public class Б : А
    {
        private int _поле1 = 20;        
        public Б() : base()
        {
            Свойство1 = "Конструктор Б";
            Метод1();
        }
        public Б(int i) : this()
        {
            Свойство1 = "Конструктор Б(int i)";
            Метод1();
        }
    }
}    



Будет переведен в код 1С: Предприятие

Исходный код 1С:Предприятие

Модуль ПространствоИмен1_ПИ2
//Класс А
Функция А(_this) Экспорт
    //Инициализация полей
    _this.Вставить("_поле1", 10)
    _this.Вставить("__type", "ПИ2.А")
    //Свойство1 = "Конструктор А";
    Возврат _this;
КонецФункции; //А(_this) Экспорт
Функция А_Получить_Поле1(_this)
    //return _поле1;
КонецФункции;
Процедура А_Установить_Поле1(_this, value)
    //_поле1 = value;
КонецПроцедуры;
Функция А_Получить_Свойство1(_this)
    Возврат _this._private_А_Свойство1;
КонецФункции;
Процедура А_Установить_Свойство1(_this, value)
    _this._private_А_Свойство1 = value;
КонецПроцедуры;
Процедура А_Метод1(_this)
    //Свойство1 = "Метод1";
КонецПроцедуры;
//Класс Б
Функция Б(_this) Экспорт
    //Инициализация полей
    _this.Вставить("_поле1", 20)
    //Вызов конструктора базового класса
    А(_this);
    _this.Вставить("__type", "ПИ2.Б")
    //Свойство1 = "Конструктор Б";
    //Метод1();
    Возврат _this;
КонецФункции; //Б(_this) Экспорт
Функция Б(_this, i) Экспорт
    //Вызов другого конструктора
    Б(_this);
    _this.Вставить("__type", "ПИ2.Б")
    //Свойство1 = "Конструктор Б(int i)";
    //Метод1();
    Возврат _this;
КонецФункции; //Б(_this, i) Экспорт
Функция Б_Получить_Поле1(_this)
    Возврат А_Получить_Поле1(_this);
КонецФункции;
Процедура Б_Установить_Поле1(_this, value)
    А_Установить_Поле1(_this);
КонецПроцедуры;
Функция Б_Получить_Свойство1(_this)
    Возврат А_Получить_Свойство1(_this);
КонецФункции;
Процедура Б_Установить_Свойство1(_this, value)
    А_Установить_Свойство1(_this);
КонецПроцедуры;
Процедура Б_Метод1(_this)
    А_Метод1(_this);
КонецПроцедуры;
 

roslyn ооп

См. также

Языки и среды Программист Платформа 1С v8.3 Бесплатно (free)

Будем писать свои скрипты на питоне и запускать их на 1С.

15.04.2024    4035    YA_418728146    13    

62

Мобильная разработка Языки и среды 1С:Элемент Программист Бесплатно (free)

Flutter может быть использован с 1С:Предприятием для разработки кроссплатформенных мобильных приложений, обеспечивая единый интерфейс и функциональность на устройствах под управлением iOS и Android. Это позволяет создавать приложения с высокой производительностью благодаря использованию собственного движка рендеринга Flutter. Интеграция Flutter с 1С:Предприятием позволяет создавать мобильные приложения любого уровня сложности, интегрировать их в корпоративные информационные системы, а также реализовывать бизнес-логику

19.03.2024    18320    ROk_dev    74    

43

Языки и среды Программист Стажер Платформа 1С v8.3 Бесплатно (free)

Существует множество языков программирования, и каждый имеет свои особенности по работе с типами данных. Слабые, явные, динамические и другие... Но кто же здесь 1С и почему с приходом "строгой" типизации EDT 1С-программистам стоит задуматься над изменением своих привычек.

16.01.2024    7332    SeiOkami    25    

61

Языки и среды Программист Бесплатно (free)

Пример небольшого приложения, с которого можно начать изучать язык программирования Dart.

08.08.2023    4206    acvatoris    6    

15

Языки и среды Программист Платформа 1С v8.3 Россия Бесплатно (free)

Написание статического анализатора для 1С традиционным способом на Си.

30.06.2023    3496    prohorp    15    

12

Языки и среды Программист Абонемент ($m)

Поставили нам задачу - вынести на отдельный сервер функционал получения заказов от клиентов по электронной почте, парсинг полученных XLS в приемлемый вид и трансформация заказов в красивый JSON, понятный нашей учетной системе на 1С. Всю эту красоту желательно запустить в отдельном докер - контейнере, по возможности не тратя лицензии, поэтому отдельно стоящую конфигурацию на БСП отвергаем сразу. Можно было бы собрать всё на Apache Airflow или Apache NiFi, но решили попробовать реализовать всю логику без Open Source, будем делать свой ETL, с Исполнителем, который в версии 3.0 научился взаимодействовать с электронной почтой по IMAP. Начнем с середины - сначала напишем скрипты, а потом соберем их в рабочую конструкцию

1 стартмани

01.06.2023    2314    0    kembrik    2    

7

Языки и среды Программист Платформа 1С v8.3 Бесплатно (free)

При работе с 1С ORM (object relation mapping) все время преследует ощущение постоянного создания монолитного приложения — один раз привязался к какой либо сущности (например, справочник Контрагенты), и весь код заполнен ссылками на эту конкретную реализацию. Можно ли независимо разрабатывать в ORM совместимые между собой справочник «Контрагентов» и использующий его документ «Платежное поручение», но при этом избежать жестких зависимостей? Спасут ли нас микросервисы? Пример на аннотациях Java демонстрирует, как это возможно делать.

13.03.2023    1306    1CUnlimited    0    

3
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. cool.vlad4 2 26.12.14 21:18 Сейчас в теме
Elisy +1, но увы не прочитал толком код. Есть же gist в конце концов. Можно было туда код поместить. (не упущу случай похвалить microsoft, в целом они очень радуют в последнее время, бесплатная Visual Studio 2013 Community Edition, планы по выкладыванию в open source Core .Net Framework и т.п. Странно почему изначально Roslyn не сделали и пилили бы на нем все)
2. Elisy 951 27.12.14 07:20 Сейчас в теме
(1) cool.vlad4,
Код не особо интересен. Главное, что его можно скопировать к себе, если возникнет необходимость.
3. Elisy 951 27.12.14 07:26 Сейчас в теме
Изначально статья была опубликована на Хабре:
http://habrahabr.ru/post/245453/
4. matytsin_new 21 12.01.15 07:39 Сейчас в теме
Интересно, но сложно придумать обоснованное коммерческое применение.
Мой личный опыт интеграции 1с и C# убедил меня в том, что код C# не стоит пытаться транслировать в код 1с. Реализация классов C# не может быть сымитирована в 1с полностью. Полноценного ООП нет. Контроля типов нет. Самодокументирования нет. Код выполняется иначе. После долгих переборов различных способов интеграции .net и 1с я для себя выбрал вариант, когда исходный код модулей на C# тем или иным способом формируется в коде 1с. Затем? с помощью System.Reflection, создается динамическая сборка, содержащая все необходимые модули и эта сборка подгружается как Com-объект. После чего, можно работать с этим объектом в синтаксисе любого .net языка. Способ не идеальный, поскольку COM-соединения иногда ведут себя непредсказуемо (например при разрыве COM-соединения) и дорогой по времени инициализации. Однако это единственный способ, позволяющий на лету формировать свои классы, соответствующие неким уже существующим интерфейсам и разделить разработку кода C# и кода 1c между разными исполнителями с наименьшим риском. Думаю,что использовать интеграцию 1с и .NET на простых классах (без сложной логики внутри классов .net) имеет смысл только для наработки навыков сопряжения вышеозначенных технологий, поскольку простые задачи надежнее решать средствами самой 1с.
5. Elisy 951 12.01.15 14:10 Сейчас в теме
(4) matytsin_new,
До коммерческого использования далеко. Скорее пока академический интерес в новогодние каникулы. Продолжение опубликовал только что на Хабре. Суть сводится к тому, что теоретически на Visual Studio можно создать альтернативный 1С конфигуратор.
http://habrahabr.ru/post/247659/
8. zqzq 25 14.01.15 08:12 Сейчас в теме
(5) 1С и сами планируют альтернативный конфигуратор на эклипс выпустить (к 1С 8.4?), вперёд паровоза бежите.
9. Elisy 951 14.01.15 10:13 Сейчас в теме
(8) zqzq,
(5) 1С и сами планируют альтернативный конфигуратор на эклипс выпустить (к 1С 8.4?), вперёд паровоза бежите.

Наивно верить, что у 1С получится качественно сделать что-то новое?
11. AlexanderKai 27.01.15 14:18 Сейчас в теме
(8) zqzq,
Скорей всего получится, что "хотели как лучше, получилось как всегда".
6. serge_focus 4 12.01.15 18:16 Сейчас в теме
На самом деле , как мне кажется, подобные интересы вызваны во первых недостаточностью внимания со стороны 1С к разработчикам. "убогая " среда конфигуратора 1С подталкивает на такие эксперименты. Идея понравилась. Так что творческой удачи в экспериментах.
7. Darklight 33 13.01.15 16:35 Сейчас в теме
Идея интересная, и действительно, соглашусь с serge_focus, что в будущем может найти и коммерческое применение в альтернативных редактора 1С. Но, остаётся лишь вопрос эффективности получаемого кода. Насколько хорошо он будет работать. Такие конвертации из более мощного языка в менее мощный - всегда чреваты потерей эффективности конкретных алгоритмических реализаций (даже по сравнение с их аналогичной ручной реализацией на конечном языке). Эффективность и гибкость конвертации можно было бы увеличить, если бы сразу конвертировать в байт код машины 1С (что правильнее), как аналог IL-кода, платформы .NET.
И, конечно же, особняком будет стоять проблема отладки. Она тут в крайне затруднена (требует отдельной реализации генератора специфического кода, который встраивал бы отладочные конструкции, которые хоть как-то давали бы обратную связь с жутким снижением производительности). А это ставит очень большой минус для таких разработок. Но, при должном рвении, ресурсов, гениальности и терпения может выйти занятный инструмент. Но, это вряд ли - запал иссякнет раньше, либо не хватит ресурсов. Слишком тяжелый проект, даже для команды.

Была бы интересна и обратная конвертация. Из кода 1С в код C# - для реализации обратного перевода проектов, написанных на 1С в среду .NET framework. Это, как мне кажется, более перспективная и простая в реализации вещь. И оптимизация тут может достичь очень высоких результатов. Вот бы ещё движки присобачить (визуальных форм (в т.ч. печатных) и работы с БД, и метаданными - и была бы хорошая перспектива-альтернатива для 1С).
EliasShy; Elisy; +2 Ответить
10. Elisy 951 14.01.15 10:18 Сейчас в теме
(7) Darklight,

Но, остаётся лишь вопрос эффективности получаемого кода. Насколько хорошо он будет работать. Такие конвертации из более мощного языка в менее мощный - всегда чреваты потерей эффективности конкретных алгоритмических реализаций (даже по сравнение с их аналогичной ручной реализацией на конечном языке). Эффективность и гибкость конвертации можно было бы увеличить, если бы сразу конвертировать в байт код машины 1С (что правильнее), как аналог IL-кода, платформы .NET.

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

Была бы интересна и обратная конвертация. Из кода 1С в код C# - для реализации обратного перевода проектов

По идее в полноценном проекте должна быть конвертация из 1С в C#, чтобы как можно больше разработчиков переманить на свою сторону.
12. zhichkin 1524 14.11.19 23:46 Сейчас в теме
Прошло несколько лет с момента последнего комментария к этой публикации...
Тем не менее хотелось бы её возродить. Сам занимаюсь чем-то подобным =)

Мой опыт работы и общения с коллегами говорит о том, что проблемы крупных компаний, использующих 1С и знающих что такое high load не по наслышке, заставляют их всё чаще решать проблемы при помощи непосредственного использования прямых SQL запросов, прикручивания сбоку стронних систем версионирования, тестирования кода, платформ для разработки web UI, а также систем обмена данными, основанных на брокерах очередей и т.д. и т.п. Более того, как выяснилось на круглом столе по high load на последнем Infostart'е 2019 - "все 1С-ники делают это" =) =) =)

ИТ культура компаний выросла за эти годы очень сильно, а вместе с ней потребность в современных средствах разработки. 1С по прежнему не решает всех проблем и, по всей видимости, это нормально - так сложилось исторически и это фактически уже константа.

Теперь хотелось бы сказать немного о коммерческой составляющей проекта. Сразу скажу, что в проекте, о котором далее пойдёт речь, я лично не участвовал. Очень жаль, кстати =)

Как-то очень давно мне довелось познакомиться с проектом, который был рождён в недрах очень крупной и известной компании. Идея была очень простой: компания выпускала свою конфигурацию 1С для автоматизации розничной торговли. Клиентов было много и с каждой копии проданной программы нужно было что-то платить 1С. А ведь наверное можно было бы не делать этого, подумали руководители этой организации...

Проблема была в том, что с нуля кассовый софт со всем его функционалом писать было дорого, а сэкономить очень хотелось. В итоге пара программистов C# сделала конвертер всей конфигурации 1С на C#. С формами, кодом всех модулей, структурами данных и прочим. Примерно год работы. Конвертер получился настолько удачным, что в принципе он мог конвертировать почти любую конфигурацию 1С. В любом случае для своих целей и своей конфигурации ребятам вполне этого конвертера было достаточно.

Бомба, не правда ли ? Однако, дальше произошло что-то удивительное. По слухам очень влиятельные люди из компании 1С лично встретились с руководством этой "жадной" компании и им удалось договориться проект закрыть. Так это или нет, но проект действительно закрыли и результаты этого проекта канули в Лету.

Эта история заставляет меня думать, что коммерческой составляющей в этом проекте вполне достаточно. Особенно в свете последних изменений ситуации с high load в крупных компаниях, плюс развитие web проектов, проектов по интеграции всего и вся со всем и всюду. Лицензионное соглашение по web сервисам от 1С... Это же вообще золотая жила какая-то!

Так что было бы интересно возродить этот проект =) Только не C# транслировать в 1С, а наоборот, как это однажды уже было сделано в рамках отдельно взятой компании =)
13. Elisy 951 15.11.19 06:32 Сейчас в теме
(12)
Чтобы транслировать 1С в C#, нужно на стороне C# иметь стройную систему классов. Транслятор C# в 1С как раз создает систему классов и интерфейсов, совместимых с объектами 1С. Если кода на C# будет наработано много, можно задуматься об обратной конвертации, ведь будет известно код 1С во что нужно конвертировать.
14. tormozit 7229 27.04.20 07:45 Сейчас в теме
(12) Интересует конвертор кода C в C#. У меня довольно простая задача https://forum.mista.ru/topic.php?id=853975 . Есть ли какие то наработки?
15. Elisy 951 27.04.20 13:20 Сейчас в теме
(14) К сожалению, с такой задачей не сталкивался
Оставьте свое сообщение