Create MyLibrary.dll
and add following code:
namespace MyTypesNamespace
{
public abstract class BaseItem
{
public abstract bool Use(object onMyObject);
}
public class Door
{
public bool IsLocked { get; set; }
public bool Open()
{
if (IsLocked)
{
System.Console.WriteLine("Cannot open door. It is locked!");
return false;
}
//Some code
System.Console.WriteLine("Door is opened!");
return true;
}
}
}
In your main project, add reference to MyLibrary.dll
and the following method:
private static List<BaseItem> loadItems(string fromCode)
{
CodeDomProvider codeProvider = new CSharpCodeProvider();
// add compiler parameters
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.CompilerOptions = "/target:library /optimize";
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = true;
compilerParams.IncludeDebugInformation = false;
compilerParams.ReferencedAssemblies.Add("mscorlib.dll");
compilerParams.ReferencedAssemblies.Add("System.dll");
compilerParams.ReferencedAssemblies.Add("MyLibrary.dll");
// compile the code
CompilerResults results = codeProvider.CompileAssemblyFromSource(compilerParams, fromCode);
var items = new List<BaseItem>();
foreach (var itemType in results.CompiledAssembly.DefinedTypes)
{
ConstructorInfo ctor = itemType.GetConstructor(Type.EmptyTypes);
object instance = ctor.Invoke(null);
items.Add(instance as BaseItem);
}
return items;
}
Usage:
private static void Main()
{
string code = loadCode();
List<BaseItem> items = loadItems(code);
BaseItem rustyKey = items[0];
BaseItem unlockAnyDoor = items[1];
Door myDoor = new Door { IsLocked = true };
rustyKey.Use(myDoor);
unlockAnyDoor.Use(myDoor);
rustyKey.Use(myDoor);
Console.ReadLine();
}
private static string loadCode()
{
return @"
using MyTypesNamespace;
public class RustyKey : BaseItem
{
public override bool Use(object onMyObject)
{
var door = onMyObject as Door;
return door.Open();
}
}
public class UnlockAnyDoor : BaseItem
{
public override bool Use(object onMyObject)
{
var door = onMyObject as Door;
door.IsLocked = false;
System.Console.WriteLine(""Door is unlocked!"");
return true;
}
}
";
}
Output: (See the output online)
Cannot open door. It is locked!
Door is unlocked!
Door is opened!
Edit:
You can simplify future code supply (which will be read from file) by eliminating code duplication. Let's generateItemClass
method which will take className
and body of Use()
method:
private static string generateItemClass(string className, string useBody)
{
return $@"
public class {className} : BaseItem
{{
public override bool Use(object onMyObject)
{{
{useBody}
}}
}}";
}
Don't forget to add using MyTypesNamespace;
for all classes.
private static string loadCode()
{
string namespaces = @"using MyTypesNamespace;";
string rustyKeyClass = generateItemClass("RustyKey",
@"var door = onMyObject as Door;
return door.Open();");
string unlockAnyDoorClass = generateItemClass("UnlockAnyDoor",
@"var door = onMyObject as Door;
door.IsLocked = false;
System.Console.WriteLine(""Door is unlocked!"");
return true;");
return namespaces + rustyKeyClass + unlockAnyDoorClass;
}