nBuilder Testdatagenerator and Reflection - c#

I'm using nBuilder to generate some Testdata for my application.
First I tested it and it worked fine.
An easy Example:
Customer customer = Builder<Customer>
.CreateNew()
.Build();
Creates a Object and fills all Properties automatically.
By Example, if customer Contains the attribute: name, it will fill it with name1
and so on...
Well all this works fine, but I have troubles to do that whole thing dynamically now.
What I'm doing now, is Reflection, I'm iterating through all Entities in my Class and foreach of them there should be generated some Testdata, even lookups and childlists should be filled, but thats not a problem.. My question is, how I'm using the above code with any type?
ANYTYPE object = Builder<ANYTYPE> ...
What I tried:
object entity = null; //The object/Entity
Assembly assembly = Assembly.GetAssembly(typeof(EMI_ERPContext)); //Getting Assembly
Type type = assembly.GetType(entityName); //I know the Type
//entity = Activator.CreateInstance(type); Do I must create an Instance here?
object entity = Builder<dynamic> //The above code.. Tried to put dynamic as Type, but doesnt work
.CreateNew()
.Build();

I tested with a console app (complete here), faking the classes / interfaces / methods of nBuilder.
So this works, but not tried in real context.
The method you could reuse is "TryToReflectBuilder". It could be much less verbose, but I let the "Step by step" code, as it's probably more explicit. ReflectionConsole.Test is used as the "entity to reflect".
namespace ReflectionConsole {
class Program {
static void Main(string[] args)
{
object test = TryToReflectBuilder("ReflectionConsole.Test");
Console.ReadKey();
}
public static object TryToReflectBuilder(string type)
{
//getting the assembly : not same as your way, but... that wasn't a problem for you
var assembly = Assembly.GetAssembly(typeof(Test));
//getting the entityType by name.
var entityType = assembly.GetType(type);
//The interesting (I hope) part is starting (yeah)
//get the Builder<T> type
var builderClassType = typeof(Builder<>);
//create generic argument for Builder<T> will take the type of our entity (always an array)
Type[] args = {entityType};
//pass generic arguments to Builder<T>. Which becomes Builder<entityType>
var genericBuilderType = builderClassType.MakeGenericType(args);
//create a new instance of Builder<entityType>
var builder = Activator.CreateInstance(genericBuilderType);
//retrieve the "CreateNew" method, which belongs to Builder<T> class
var createNewMethodInfo = builder.GetType().GetMethod("CreateNew");
//invoke "CreateNew" from our builder instance which gives us an ObjectBuilder<T>, so now an ObjectBuilder<entityType> (well as an ISingleObjectBuilder<entityType>, but... who minds ;))
var objectBuilder = createNewMethodInfo.Invoke(builder, null);
//retrieve the "Build" method, which belongs to ObjectBuilder<T> class
var buildMethodInfo = objectBuilder.GetType().GetMethod("Build");
//finally, invoke "Build" from our ObjectBuilder<entityType> instance, which will give us... our entity !
var result = buildMethodInfo.Invoke(objectBuilder, null);
//it would be sad to return nothing after all these efforts, no ??
return result;
}
}
public class Builder<T>
{
public static ISingleObjectBuilder<T> CreateNew()
{
Console.WriteLine(string.Format("{0} creating new",typeof(T)));
return new ObjectBuilder<T>();
}
}
public interface ISingleObjectBuilder<T> : IBuildable<T>
{
}
public interface IObjectBuilder<T> : ISingleObjectBuilder<T>
{
}
public interface IBuildable<T>
{
T Build();
}
public class ObjectBuilder<T> : ISingleObjectBuilder<T>
{
public T Build()
{
Console.WriteLine(string.Format("{0} building myself", typeof(T)));
return Activator.CreateInstance<T>();
}
}
public class Test
{
}
}

Related

Using dynamically generated type for variable declaration and assignment

Following this question, it is possible to create a type and an instance form it dynamically like this:
var type = typeof(AnimalContext<>).MakeGenericType(a.GetType());
var a_Context = Activator.CreateInstance(type);
Great.
However, what I want to do instead of creating an instance of a determined type with Activator.CreateInstance(type);is to use a dynamic created type to declare a variable, and assign an instance to my dynamically created type.
Kind of:
myDynamicallyCreatedType variableName = figuredTypeInstace;
But I cannot use the created type(var type = typeof(AnimalContext<>).MakeGenericType(a.GetType()); for declarations. Is that possible?
Edit:
Short scenario explanation where the need came up. I need to call a method that will be called from a "topManager", this topManager holds the respective instance of the types type1Manager and type2Manager that implement the same base interface IMyInterface method ImplementedMethod.
What I am trying to do, could be solved with ifs, like this:
private int HandleInstance(Type itemType, //other args) {
if (itemType == Type.type1) {
topManagerInstance.manager1Instance.ImplementedMethod(//args):
}
elseif (itemType == Type.type2) {
topManagerInstance.manager2Instance.ImplementedMethod(//args):
}
...not meaningful code
{
But, I was wondering if it could be solved handling types to avoid the ifs, like (caps used to spot the key of the question out, not to shout):
private int HandleInstance(Type itemType, //other args) {
Type managerType = itemType == Type.type1 ? typeof(manager1Type) :
typeof(manager2Type);
Type[] managerTypeArray = { managerType, typeof(int) };
var myDynamicallyCreatedType = typeof(IMyInterface<,>).MakeGenericType(managerTypeArray);
//KEY OF THE QUESTION. THIS IS WHAT I AM ASKING FOR
//assign created variable to dynamic created type to call respective method
myDynamicallyCreatedType variableName = topManagerInstance.type1Manager;
//base type. any type1ManagerType or type2ManagerType to be assigned, as
//they inherit from the same IMyInterface<,>, and the type created is
//generic
variableName.ImplementedMethod(//args):
}
It seems like you're just looking to map an enum value to a function call in a specific implementation. One way to do that is to have a factory class that handles it with a Dictionary used as a map. For example:
Given a setup something like this:
// The enum you use for mapping
public enum Thing
{
Foo,
Bar
}
// The various implementations...
public interface ISomeInterface
{
void SomeMethod();
}
public class Foo : ISomeInterface
{
public void SomeMethod() => Console.WriteLine("Foo method!");
}
public class Bar : ISomeInterface
{
public void SomeMethod() => Console.WriteLine("Bar method!");
}
Now you could have a factory that looks like this:
public class MyThingFactory
{
private Dictionary<Thing, ISomeInterface> _registry;
public MyThingFactory()
{
_registry = new Dictionary<Thing, ISomeInterface>
{
{Thing.Foo, new Foo()},
{Thing.Bar, new Bar()},
};
}
public void RunMethod(Thing thing)
{
if(!_registry.TryGetValue(thing, out var item))
{
throw new ArgumentOutOfRangeException(nameof(thing));
}
item.SomeMethod();
}
}
And call it like this:
// You may want to make this static for performance reasons since you won't recreate
// the dictionary every time
var factory = new MyThingFactory();
factory.RunMethod(Thing.Foo);
factory.RunMethod(Thing.Bar);
//Output:
//Foo method!
//Bar method!

Get class from Type with Reflection and call a generic constructor with Type in C#

I am working with Dapper and I want to iterate through my model classes and set type mapping for any class having a field decorated with a ColumnAttribute.
public class ColumnAttributeTypeMapper<T> : FallbackTypeMapper
{
public static readonly string ColumnAttributeName = "ColumnAttribute";
public ColumnAttributeTypeMapper()
: base(new SqlMapper.ITypeMap[]
{
new CustomPropertyTypeMap(typeof (T), SelectProperty),
new DefaultTypeMap(typeof (T))
})
{
}
// implementation of SelectProperty and so on...
// If required, full implementation is on https://gist.github.com/senjacob/8539127
}
In my model class library, I'm iterating through all possible types; now I need to call the generic ColumnAttributeTypeMapper<T> constructor with the class of the type.
using System.Web;
using Dapper;
[assembly : PreApplicationStartMethod(typeof(Model.Initiator), "RegisterTypeMaps")]
namespace Model
{
class Initiator
{
public static void RegisterTypeMaps()
{
var mappedTypes = Assembly.GetAssembly(typeof (Initiator)).GetTypes().Where(
f =>
f.GetProperties().Any(
p =>
p.GetCustomAttributes(false).Any(
a => a.GetType().Name == ColumnAttributeTypeMapper<dynamic>.ColumnAttributeName)));
// I want to skip registering each class manually :P
// SqlMapper.SetTypeMap(typeof(Model1), new ColumnAttributeTypeMapper<Model1>());
// SqlMapper.SetTypeMap(typeof(Model2), new ColumnAttributeTypeMapper<Model2>());
foreach (var mappedType in mappedTypes)
{
SqlMapper.SetTypeMap(mappedType, new ColumnAttributeTypeMapper<mappedType>());
}
}
}
}
How can I pass the class from type instead of type 'mappedType' to new ColumnAttributeTypeMapper<classof(mappedType)?>()
I found this as a similar question, but I need to call the generic constructor instead of a generic method with the Type.
If it can not be done, could you please explain the reason?
Answer
This is how the mapping worked as suggested by Tom.
var mapper = typeof(ColumnAttributeTypeMapper<>);
foreach (var mappedType in mappedTypes)
{
var genericType = mapper.MakeGenericType(new[] { mappedType });
SqlMapper.SetTypeMap(mappedType, Activator.CreateInstance(genericType) as SqlMapper.ITypeMap);
}
You will need the method Type.MakeGenericType; usage is as follows:
var columnType = typeof(ColumnAttributeTypeMapper<>);
var genericColumn = columnType.MakeGenericType(new[] {typeof(mappedType)});
var instance = Activator.CreateInstance(genericColumn);
I'm writing this without intellisense and only having skimmed your code, so please let me know whether I've made any mistakes and I'll correct them.

Property Type as Generic parameter

I'm trying to figure out how I can make a Generics call take a variable for the Type. In the call below it take a type "DAL.Account" and works fine.
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
I want to change that so that I can pass a variable in place of the "DAL.Account". Something like this but I know that won't work as you can't pass property as a Type.
ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray())
Below is the shell pieces of code I think explains what I'm trying to do. Generics is not my strong suit so I'm looking for some help. Is there anyway that I can make this happen?
//Stores a "Type" that indicates what Object is a Criteria for.
public class AccountCriteria : IGeneratedCriteria
{
...
public Type EntityType
{
get {return typeof(DAL.Account);}
}
}
//I have added a function to the DataContext called "GetTable"
// And then used it as an example in a Console App to test its functionality.
public class ADRPDataContext : NHibernateDataContext
{
...
public CodeSmith.Data.NHibernate.ITable<T> GetTable<T>() where T : EntityBase
{
var tb = new CodeSmith.Data.NHibernate.Table<T>(this);
return tb;
}
}
// console application that uses DataContext.GetTable
class Program
{
static void Main(string[] args)
{
using (var ctx = new ADRPDataContext())
{
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
}
}
}
//ExistsCommand class that uses the EntityType property of the Critera to generate the data.
public class ExistsCommand
{
private IGeneratedCriteria Criteria { get; set; }
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
//This was my first attempt but doesn't work becuase you can't pass a property in for a Type.
//But I can figure out how to write this so that it will work.
Result = ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
You are looking to instantiate a generic type. Some info can be found here
This is a simple example demonstrating how to instantiate a List with a capacity of 3. Here is a method that you can call to create a generic when you don't know the type:
public static Object CreateGenericListOfType(Type typeGenericWillBe)
{
//alternative to the followin:
//List<String> myList = new List<String>(3);
//build parameters for the generic's constructor (obviously this code wouldn't work if you had different constructors for each potential type)
object[] constructorArgs = new Object[1];
constructorArgs[0] = 3;
//instantiate the generic. Same as calling the one line example (commented out) above. Results in a List<String> with 3 list items
Type genericListType = typeof(List<>);
Type[] typeArgs = { typeGenericWillBe };
Type myNewGeneric = genericListType.MakeGenericType(typeArgs);
object GenericOfType = Activator.CreateInstance(myNewGeneric, constructorArgs);
return GenericOfType;
}
And here is some sample code that will show you the example method works:
List<String> Strings = (List<String>)InstantiateGenericTypeWithReflection.CreateGenericListOfType(typeof(String));
//demonstrate the object is actually a List<String> and we can do stuff like use linq extensions (isn't a good use of linq but serves as example)
Strings.Add("frist");
Strings.Add("2nd");
Strings.Add("tird");
Console.WriteLine("item index 2 value: " + Strings.Where(strings => strings == "2").First());
In your example, replace your GetTable<Criteria.EntityType>() with CreateGenericTableOfType(Criteria.EntityType). This will return a generic table of whatever type you pass in. You will of course need to implement the method properly (handle constructor args, change List to Table etc).
I think you need to change the way you're doing this slightly, and instead use generics instead of the EntityType property. Perhaps something along the lines of the following:
// Create an abstract class to be used as the base for classes that are supported by
// ExistsCommand and any other classes where you need a similar pattern
public abstract class ExtendedCriteria<T> : IGeneratedCriteria
{
public ExistsCommand GetExistsCommand()
{
return new ExistsCommand<T>(this);
}
}
// Make the non-generic ExistsCommand abstract
public abstract class ExistsCommand
{
protected abstract void DataPortal_Execute();
}
// Create a generic sub-class of ExistsCommand with the type parameter used in the GetTable call
// where you were previously trying to use the EntityType property
public class ExistsCommand<T> : ExistsCommand
{
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
Result = ctx.GetTable<T>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
// Derive the AccountCriteria from ExtendedCriteria<T> with T the entity type
public class AccountCriteria : ExtendedCriteria<DAL.Account>
{
...
}

MOQ returning dynamic types as object issue

pologise if this questions has been asked but I couldn't find the answer anywhere.
My problem is when mocking a return method using MOQ where that method returns a dynamic type. I'm using a third part library which uses dynamic times. MOQ seems to cast the dynamic type as object.
Mock<IFacebookHelper> mockFbHelp = new Mock<IFacebookHelper>();
mockFbHelp.Setup(x => x.Get("me")).Returns(new { email = "test#test.com", id="9999" });
Method in the mocked helper.
public dynamic Get(string p)
{
var client = new FacebookClient(AccessToken);
return client.Get("me");
}
Code from controller using mocked results.
_facebookHelper.AccessToken = accessToken;
dynamic result = _facebookHelper.Get("me");
int facebookId = int.Parse(result.id); //This errors as id doesn't exist.
Basically MOQ has returned a dynamic type of object that would require casting as something.
Does anyone know how to get around this problem? I'm assuming it may be because MOQ is not coded in .NET 4 therefore does not support dynamic types?
Edit
Actually I don't think this is a MOQ issue as I created my own mock class and still had the same problem. I'm new to dynamic types though so not sure what's going on.
Edit 2 - Part answered.. Problem nothing to do with MOQ after all
Actually the problem seems to be due to the dynamic type being created in a different assembly. Although I got round my initial problem using a JObject type I still want to figure this out.
namespace MyLib.Tools
{
public interface IDynTest
{
dynamic GetData();
}
}
namespace MyLib.Tools
{
public class DynTest : Effect.Tools.IDynTest
{
public dynamic GetData() {
return new { DynamicProperty = "hello" };
}
}
}
namespace Warrior.WebUI.Infrastructure
{
public class UseDynTest
{
private readonly IDynTest dynTest;
public UseDynTest(IDynTest dynTest)
{
this.dynTest = dynTest;
}
public string RetTest()
{
return dynTest.GetData().DynamicProperty;
}
}
}
namespace Warrior.Tests
{
[TestClass]
public class TestDynTest
{
[TestMethod]
public void TestMethod1()
{
//Mock<IDynTest> mockDynTest = new Mock<IDynTest>();
//mockDynTest.Setup(x => x.GetData()).Returns(new { DynamicProperty = "From Unit Test" });
DynTestProxy dynTestProxy = new DynTestProxy();
UseDynTest useTest = new UseDynTest(dynTestProxy);
string results = useTest.RetTest();
Assert.AreEqual("From Unit Test", results);
}
}
}
namespace Warrior.Tests
{
public class DynTestProxy:IDynTest
{
public dynamic GetData()
{
return (dynamic) new { DynamicProperty = "From Unit Test" };
}
}
}
There are 3 project indicated by the Namespace MyLib, Warrior.WebUI and Warrior.Tests.
As it is the test fails with an error..
'object' does not contain a definition for 'DynamicProperty'
which occurs on RetTest()
However if I simply move the DynTestProxy class into the Warrior.WebUI project everything works fine. I'm guessing there are problems when sending dynamic types accross different assemblies or something.
I did a quick test:
namespace ConsoleApplication5
{
public interface IFacebookHelper { dynamic Get(string p); }
class Program
{
static void Main(string[] args)
{
Mock<IFacebookHelper> mockFbHelp = new Mock<IFacebookHelper>();
mockFbHelp.Setup(x => x.Get("me")).Returns(new { email = "test#test.com", id = "9999" });
dynamic result = mockFbHelp.Object.Get("me");
int facebookId = int.Parse(result.id);
string email = result.email;
}
}
}
This is working fine. I don't see a problem here.
Are you sure you didn't mix some things up?
Look at the method you posted:
public dynamic Get(string p)
{
var client = new FacebookClient(AccessToken);
return client.Get("me");
}
Maybe it should be:
...
return client.Get(p);
...
Is _facebookHelper really using the Mock object? It should be of type IFacebookHelperProxy or something like that during your test.
EDIT:
The problem is your attempt to expose an anonymous type across assembly boundaries, since you can use anonymous type only within the assembly you created them.
So instead of
public class DynTestProxy:IDynTest
{
public dynamic GetData()
{
return (dynamic) new { DynamicProperty = "From Unit Test" };
}
}
you should use an ExpandoObject:
public class DynTestProxy:IDynTest
{
public dynamic GetData()
{
dynamic r = new ExpandoObject();
r.DynamicProperty = "From Unit Test";
return r;
}
}
or use the InternalsVisibleTo attribute. See here for more information. Also this question may be interesting for you.

Purpose of Activator.CreateInstance with example?

Can someone explain Activator.CreateInstance() purpose in detail?
Say you have a class called MyFancyObject like this one below:
class MyFancyObject
{
public int A { get;set;}
}
It lets you turn:
String ClassName = "MyFancyObject";
Into
MyFancyObject obj;
Using
obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))
and can then do stuff like:
obj.A = 100;
That's its purpose. It also has many other overloads such as providing a Type instead of the class name in a string. Why you would have a problem like that is a different story. Here's some people who needed it:
Createinstance() - Am I doing this right?
C# Using Activator.CreateInstance
Creating an object without knowing the class name at design time
Well i can give you an example why to use something like that. Think of a game where you want to store your level and enemies in an XML file. When you parse this file, you might have an element like this.
<Enemy X="10" Y="100" Type="MyGame.OrcGuard"/>
what you can do now is, create dynamically the objects found in your level file.
foreach(XmlNode node in doc)
var enemy = Activator.CreateInstance(null, node.Attributes["Type"]);
This is very useful, for building dynamic enviroments. Of course its also possible to use this for Plugin or addin scenarios and alot more.
My good friend MSDN can explain it to you, with an example
Here is the code in case the link or content changes in the future:
using System;
class DynamicInstanceList
{
private static string instanceSpec = "System.EventArgs;System.Random;" +
"System.Exception;System.Object;System.Version";
public static void Main()
{
string[] instances = instanceSpec.Split(';');
Array instlist = Array.CreateInstance(typeof(object), instances.Length);
object item;
for (int i = 0; i < instances.Length; i++)
{
// create the object from the specification string
Console.WriteLine("Creating instance of: {0}", instances[i]);
item = Activator.CreateInstance(Type.GetType(instances[i]));
instlist.SetValue(item, i);
}
Console.WriteLine("\nObjects and their default values:\n");
foreach (object o in instlist)
{
Console.WriteLine("Type: {0}\nValue: {1}\nHashCode: {2}\n",
o.GetType().FullName, o.ToString(), o.GetHashCode());
}
}
}
// This program will display output similar to the following:
//
// Creating instance of: System.EventArgs
// Creating instance of: System.Random
// Creating instance of: System.Exception
// Creating instance of: System.Object
// Creating instance of: System.Version
//
// Objects and their default values:
//
// Type: System.EventArgs
// Value: System.EventArgs
// HashCode: 46104728
//
// Type: System.Random
// Value: System.Random
// HashCode: 12289376
//
// Type: System.Exception
// Value: System.Exception: Exception of type 'System.Exception' was thrown.
// HashCode: 55530882
//
// Type: System.Object
// Value: System.Object
// HashCode: 30015890
//
// Type: System.Version
// Value: 0.0
// HashCode: 1048575
You can also do this -
var handle = Activator.CreateInstance("AssemblyName",
"Full name of the class including the namespace and class name");
var obj = handle.Unwrap();
A good example could be next: for instance you have a set of Loggers and you allows user to specify type to be used in runtime via configuration file.
Then:
string rawLoggerType = configurationService.GetLoggerType();
Type loggerType = Type.GetType(rawLoggerType);
ILogger logger = Activator.CreateInstance(loggerType.GetType()) as ILogger;
OR another case is when you have a common entities factory, which creates entity, and is also responsible on initialization of an entity by data received from DB:
(pseudocode)
public TEntity CreateEntityFromDataRow<TEntity>(DataRow row)
where TEntity : IDbEntity, class
{
MethodInfo methodInfo = typeof(T).GetMethod("BuildFromDataRow");
TEntity instance = Activator.CreateInstance(typeof(TEntity)) as TEntity;
return methodInfo.Invoke(instance, new object[] { row } ) as TEntity;
}
The Activator.CreateInstance method creates an instance of a specified type using the constructor that best matches the specified parameters.
For example, let's say that you have the type name as a string, and you want to use the string to create an instance of that type. You could use Activator.CreateInstance for this:
string objTypeName = "Foo";
Foo foo = (Foo)Activator.CreateInstance(Type.GetType(objTypeName));
Here's an MSDN article that explains it's application in more detail:
http://msdn.microsoft.com/en-us/library/wccyzw83.aspx
Building off of deepee1 and this, here's how to accept a class name in a string, and then use it to read and write to a database with LINQ. I use "dynamic" instead of deepee1's casting because it allows me to assign properties, which allows us to dynamically select and operate on any table we want.
Type tableType = Assembly.GetExecutingAssembly().GetType("NameSpace.TableName");
ITable itable = dbcontext.GetTable(tableType);
//prints contents of the table
foreach (object y in itable) {
string value = (string)y.GetType().GetProperty("ColumnName").GetValue(y, null);
Console.WriteLine(value);
}
//inserting into a table
dynamic tableClass = Activator.CreateInstance(tableType);
//Alternative to using tableType, using Tony's tips
dynamic tableClass = Activator.CreateInstance(null, "NameSpace.TableName").Unwrap();
tableClass.Word = userParameter;
itable.InsertOnSubmit(tableClass);
dbcontext.SubmitChanges();
//sql equivalent
dbcontext.ExecuteCommand("INSERT INTO [TableNme]([ColumnName]) VALUES ({0})", userParameter);
Coupled with reflection, I found Activator.CreateInstance to be very helpful in mapping stored procedure result to a custom class as described in the following answer.
Why would you use it if you already knew the class and were going to cast it?
Why not just do it the old fashioned way and make the class like you always make it? There's no advantage to this over the way it's done normally.
Is there a way to take the text and operate on it thusly:
label1.txt = "Pizza"
Magic(label1.txt) p = new Magic(lablel1.txt)(arg1, arg2, arg3);
p.method1();
p.method2();
If I already know its a Pizza there's no advantage to:
p = (Pizza)somefancyjunk("Pizza"); over
Pizza p = new Pizza();
but I see a huge advantage to the Magic method if it exists.
We used it for something like e.g.
public interface IExample
{
void DoSomethingAmazing();
}
public class ExampleA : IExample
{
public void DoSomethingAmazing()
{
Console.WriteLine("AAAA");
}
public void DoA()
{
Console.WriteLine("A")
}
}
public class ExampleB : IExample
{
public void DoSomethingAmazing()
{
Console.WriteLine("BBBB");
}
public void DoB()
{
Console.WriteLine("B")
}
}
and then provided the type serialized from a settings file
=> Even after compilation we can still change the applications behaviour by using different settings
Something like e.g.
public static class Programm
{
public static void Main()
{
var type = MagicMethodThatReadsASerializedTypeFromTheSettings();
var example = (IExample) Activator.CreateInstance(type);
example.DoSomethingAmazing();
switch(example)
{
case ExampleA a:
a.DoA();
break;
case ExampleB b:
b.DoB();
break;
}
}
}
And I use it in a custom multi-user serialization where I send RPC (Remote Procedure Calls) to other devices with parameters.
Extremly cropped to the necesarry it basically does
public ISendable
{
public byte[] ToBytes();
public void FromBytes(byte[] bytes);
}
// Converts any ISendable into a byte[] with the content
// typeBytes + contentBytes
public byte[] ToBytes(ISendable toSend)
{
var typeBytes = Encoding.ASCII.GetBytes(toSend.GetType().AssemblyQualifiedName);
var contentBytes = ISendable.ToBytes();
return MagicMethodToCombineByteArrays(typeBytes, contentBytes);
}
// Coonverts back from byte[] to the according ISendable
// by first reading the type, creating the instance and filling it with
// contentBytes
public T FromBytes<T>(byte[] bytes) where T : ISendable
{
MagicMethodToSplitInputBytes(out var typeBytes, out var contentBytes);
var type = Encoding.ASCII.GetString(typeBytes);
var instance = (T) Activator.CreateInstance(type);
instance.FromBytes(contentBytes);
return instance;
}

Categories

Resources