Fill / Update Runtime Enumeration Values โ€‹โ€‹in C #

I have a windows application where I need to fill in the enum values โ€‹โ€‹at runtime by reading a text file called "Controls.txt". As a limitation, I should not use a dictionary . The following are the default values โ€‹โ€‹available in the MyControls enumeration. I should use only listings .

public enum MyControls { Button1 = 0, Button2 = 1, Button3 = 2, } 

If the Controls.txt file is available, then the contents of the enumeration should change as

 public enum MyControls { btn1 = 0, btn2 = 1, btn3 = 2, } 

how can i achieve this. I also came across the Create / Change Names link in Runtime , but couldn't figure it out.

+8
enums c # dynamic
source share
3 answers

I strongly think that you are trying to solve the wrong problem. The value of an enumeration is type safety. I do not think that its dynamic content is a good idea. What would really be useful is to have correspondence filled with a text file (for example) before compilation. You can do this using text patterns in VS.

You can find an example on my blog: http://skleanthous.azurewebsites.net/post/2014/05/21/Creating-enums-from-the-database-and-using-them-in-Entity-framework-5- and-later-in-model-first

Although my example is loading from db, changing it to load from a text file should be trivial.

+4
source share

Besides the fact that I agree with another answer that says that you lose type and compile time security using EnumBuilderClass , there should be a single way (thanks huMpty duMpty ).

 // sample "file": string fileContent = @" btn1 = 0, btn2 = 1, btn3 = 2, "; var enumBody = fileContent.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) .Select(line => new { bothToken = line.Trim().Trim(',').Split('=') }) .Where(x => x.bothToken.Length == 2) .Select(x => new { Name = x.bothToken[0].Trim(), Value = int.Parse(x.bothToken[1].Trim()) }); AppDomain currentDomain = AppDomain.CurrentDomain; AssemblyName asmName = new AssemblyName("EnumAssembly"); AssemblyBuilder asmBuilder = currentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave); ModuleBuilder mb = asmBuilder.DefineDynamicModule(asmName.Name, asmName.Name + ".dll"); string enumTypeName = string.Format("{0}.{1}", typeof(MyControls).Namespace, typeof(MyControls).Name); EnumBuilder eb = mb.DefineEnum(enumTypeName, TypeAttributes.Public, typeof(int)); foreach(var element in enumBody) { FieldBuilder fb1 = eb.DefineLiteral(element.Name, element.Value); } Type eType = eb.CreateType(); foreach (object obj in Enum.GetValues(eType)) { Console.WriteLine("{0}.{1} = {2}", eType, obj, ((int)obj)); } 

Output:

 Namespacename.MyControls.btn1 = 0 Namespacename.MyControls.btn2 = 1 Namespacename.MyControls.btn3 = 2 
+3
source share

Well, I agree that the use case described above is not something that I would use. However, I do not agree when it comes to the fact that it is useless. For example, we use enumerations to classify string values โ€‹โ€‹for machine learning modules. We write code at runtime to use it at runtime, and grouping enumerations is much faster than grouping and parsing strings. There is nothing good when using strings in great qualities. They are problematic when comparing, allocating memory, garbage collection, grouping, sorting, too many bytes.

Databases that manage large amounts of data will generate a hash of the string and store it, then compare the hash of the strings (not unique, but the number) and the string in a single expression, forcing TSQL to use a more specific index in the hash field. to narrow down your search and then compare string values โ€‹โ€‹to make sure the correct value is being used. in TSQL this can be done like this:

 SELECT * FROM Production.Product WHERE CHECKSUM(N'Bearing Ball') = cs_Pname AND Name = N'Bearing Ball'; GO 

but on .net we keep thinking that string comparison is the way to go.

It makes no sense for me to drop my code here, since it is proprietary, but there are many good examples, an article by Bob Dane shows line by line how this can be done, and is located here

. A fragment of his decision is as follows:

 using System; using System.Reflection; using System.IO; namespace RemoteUser { public class RemoteUserClass { public RemoteUserClass() { // Load the remote assembly AssemblyName name = new AssemblyName(); name.CodeBase = "file://" + Directory.GetCurrentDirectory() + "ThirdPartyDll.dll"; Assembly assembly = AppDomain.CurrentDomain.Load(name); // Instantiate the class object remoteObject = assembly.CreateInstance("ThirdPartyDll.ThirdPartyClass"); Type remoteType = assembly.GetType("ThirdPartyDll.ThirdPartyClass"); // Load the enum type PropertyInfo flagsInfo = remoteType.GetProperty("ThirdPartyBitFields"); Type enumType = assembly.GetType("ThirdPartyDll.BitFields"); // Load the enum values FieldInfo enumItem1 = enumType.GetField("AnotherSetting"); FieldInfo enumItem2 = enumType.GetField("SomethingElse"); // Calculate the new value int enumValue1 = (int)enumItem1.GetValue(enumType); int enumValue2 = (int)enumItem2.GetValue(enumType); int currentValue = (int)flagsInfo.GetValue(remoteObject, null); int newValue = currentValue | enumValue1 | enumValue2; // Store the new value back in Options.FieldFlags object newEnumValue = Enum.ToObject(enumType, newValue); flagsInfo.SetValue(remoteObject, newEnumValue, null); // Call the method MethodInfo method = remoteType.GetMethod("DoSomeGood"); method.Invoke(remoteObject, null); } } } 

You can use the System.Reflection.Emit namespace for many things, you can create a class that creates a license key for it. You can also write code, and code writing and updating code is the future.

+1
source share

All Articles