Установить местоположение TypeBuilder.CreateType ()? - PullRequest
2 голосов
/ 21 мая 2019

Я создаю класс c # во время выполнения в .NET 4.7.2 с помощью TypeBuilder.Проблема в том, что DLL для типа хранится в корневой папке текущего приложения.Проблема в том, что часто пользователь не имеет прав записи в локальную корневую папку.

Так как мне установить место, где сборки должны быть сохранены и загружены?И какая папка пользователя подойдет для этого?

Текущий код:

private static Type CreateRaportType(List<PropertieInformation> propertieList, string className)
        {
            AssemblyName assemblyName;
            AssemblyBuilder assemblyBuilder;
            ModuleBuilder module;
            TypeBuilder typeBuilder;
            FieldBuilder field;
            PropertyBuilder property;
            MethodAttributes GetSetAttr;
            MethodBuilder currGetPropMthdBldr;
            MethodBuilder currSetPropMthdBldr;
            ILGenerator currGetIL;
            ILGenerator currSetIL;

            Type caType;
            CustomAttributeBuilder caBuilder;

            List<Object> objList = new List<object>();

            assemblyName = new AssemblyName();
            assemblyName.Name = "ReportAssembly";

            assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
            module = assemblyBuilder.DefineDynamicModule("ReportModule");

            typeBuilder = module.DefineType(className, TypeAttributes.Public | TypeAttributes.Class, typeof(GeneratedClassBase));

            foreach (PropertieInformation propertieInfo in propertieList)
            {
                field = typeBuilder.DefineField("_" + propertieInfo.PropertieName, propertieInfo.PropertieType, FieldAttributes.Private);

                property = typeBuilder.DefineProperty(propertieInfo.PropertieName, PropertyAttributes.None, propertieInfo.PropertieType, new Type[] { propertieInfo.PropertieType });
                GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig;

                currGetPropMthdBldr = typeBuilder.DefineMethod("get_value", GetSetAttr, propertieInfo.PropertieType, Type.EmptyTypes);

                currGetIL = currGetPropMthdBldr.GetILGenerator();
                currGetIL.Emit(OpCodes.Ldarg_0);
                currGetIL.Emit(OpCodes.Ldfld, field);
                currGetIL.Emit(OpCodes.Ret);

                currSetPropMthdBldr = typeBuilder.DefineMethod("set_value", GetSetAttr, null, new Type[] { propertieInfo.PropertieType });

                currSetIL = currSetPropMthdBldr.GetILGenerator();
                currSetIL.Emit(OpCodes.Ldarg_0);
                currSetIL.Emit(OpCodes.Ldarg_1);
                currSetIL.Emit(OpCodes.Stfld, field);
                currSetIL.Emit(OpCodes.Ret);

                // Last, we must map the two methods created above to our PropertyBuilder to
                // their corresponding behaviors, "get" and "set" respectively. 
                property.SetGetMethod(currGetPropMthdBldr);
                property.SetSetMethod(currSetPropMthdBldr);

                caType = typeof(Reportable);
                objList.Clear();
                objList.Add(propertieInfo.MemberToDataBind);
                objList.Add(propertieInfo.ControlToUse);
                objList.Add(propertieInfo.PropertieName);

                if (propertieInfo.ControlToUse == ControlToUse.SystemItemTable)
                {
                    objList.Add(propertieInfo.PropertieInnerCollectionType);
                    objList.Add(propertieInfo.PropertieInnerCollectionName);
                    objList.Add(propertieInfo.DisplayName);
                    objList.Add(-1);
                    objList.Add(FieldListIcon.UnUsedItem);
                    objList.Add(propertieInfo.SystemItemKey);
                    objList.Add(null);
                }
                else if (propertieInfo.ControlToUse == ControlToUse.AttributeTable)
                {
                    objList.Add(null);
                    objList.Add(null);
                    objList.Add(null);
                    objList.Add(propertieInfo.MultiAttributeId);
                    objList.Add(FieldListIcon.UnUsedItem);
                    objList.Add(null);
                    objList.Add(null);
                }
                else if (propertieInfo.ControlToUse == ControlToUse.GUIGroupTable)
                {
                    objList.Add(propertieInfo.PropertieInnerCollectionType);
                    objList.Add(propertieInfo.PropertieInnerCollectionName);
                    objList.Add(propertieInfo.DisplayName);
                    objList.Add(-1);
                    objList.Add(FieldListIcon.UnUsedItem);
                    objList.Add(null);
                    objList.Add(propertieInfo.GuiGroupKey);
                }
                else
                {
                    objList.Add(null);
                    objList.Add(null);
                    objList.Add(null);
                    objList.Add(-1);
                    objList.Add(FieldListIcon.UnUsedItem);
                    objList.Add(null);
                    objList.Add(null);
                }

                var conInfo = caType.GetConstructor(Type.EmptyTypes);
                var conArgs = new object[] { };
                var caTypeFields = caType.GetFields();

                caBuilder = new CustomAttributeBuilder(conInfo, conArgs, caTypeFields, objList.ToArray());

                property.SetCustomAttribute(caBuilder);

                caType = typeof(DisplayNameAttribute);

                if (propertieInfo.IsList)
                    caBuilder = new CustomAttributeBuilder(caType.GetConstructor(new Type[] { typeof(string) }), new string[] { propertieInfo.DisplayName });
                else
                    caBuilder = new CustomAttributeBuilder(caType.GetConstructor(new Type[] { typeof(string) }), new string[] { propertieInfo.DisplayName });

                property.SetCustomAttribute(caBuilder);
            }
            return typeBuilder.CreateType();
        }

1 Ответ

0 голосов
/ 21 мая 2019

Для сохранения динамической сборки в пользовательскую папку вы можете использовать перегруженный метод DefineDynamicAssembly в AppDomain

AppDomain currDom = AppDomain.CurrentDomain;
AssemblyName aName = new AssemblyName();
aName.Name = "YouAssemblyName";
string  moduleName = aName.Name + ".dll";
AssemblyBuilder ab = currDom.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save, @"FOLDER\TO\YOUR\ASSEMBLY");
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, moduleName);
TypeBuilder tb = mb.DefineType("Example");
tb.CreateType();
// type definition here
ab.Save(moduleName);

Для автоматической загрузки сборки из пользовательского места вы можете использовать событие TypeResolve для AppDomain

AppDomain.CurrentDomain.TypeResolve += CurrentDomain_TypeResolve;

Assembly CurrentDomain_TypeResolve(object sender, ResolveEventArgs args) 
{
        return Assembly.LoadFrom(/*path to your saved assembly*/); 
}

Хорошая папка для этой цели: driveletter: \ Users \\ AppData \ Local \ YourFolder.Используйте метод GetFolderPath, чтобы получить его путь:

Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); 

ps Я немного подправил пример из этого документа: https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.typeresolve?view=netframework-4.8

ОБНОВЛЕНО:

InitialВопрос был о том, как сохранить / загрузить динамическую сборку в / из пользовательского расположения.Но если необходимо определить динамический модуль и типы в памяти в одном AppDomain и вам не нужно сохранять динамическую сборку, то достаточно вызвать AssemblyBuilder.DefineDynamicAssembly с AssemblyBuilderAccess.Run , а затем определите переходный динамический модуль, используя метод AssemblyBuilder.DefineDynamicModule (string) .Наконец, вам нужно вызвать AssemblyBuilder.GetType (string, bool) , чтобы получить ваш тип.

Код будет выглядеть так:

AppDomain currDom = AppDomain.CurrentDomain;
AssemblyName aName = new AssemblyName();
aName.Name = "YourAssemblyName";
AssemblyBuilder assemblyBuilder = currDom.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run); // We need Run access, don't need Save access
ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(aName.Name); // Here we define transient dynamic module in assembly

TypeBuilder tb = mb.DefineType("YourTypeName");
tb.CreateType();       

// Define your type definition here
// ...

Type t = assemblyBuilder.GetType("YourTypeName", true); // Load created type using our AssemblyBuilder instance
Console.WriteLine("Loaded type \"{0}\".", t);
Object o = Activator.CreateInstance(t); // Create object of loaded type
Console.WriteLine("Created object \"{0}\".", o.ToString());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...