Unable to pass Delegation Object across AppDomain in C# due to SerializationException - c#

I am trying to create and pass a Delegate from one AppDomain to another.
But it throws Error only when passing Delegates. If objects like String are passed, it works fine.
Also If the delegate is removed from setting through a constructor and set using a method, I am still unable to pass it to the object.
namespace TESTNS1 {
class Program {
static void Main(string[] args) {
try {
Program obj = new Program();
NS22.testappdom.MYDelT tt = new NS22.testappdom.MYDelT(obj.testingg);
NS22.testappdom obb = new NS22.testappdom(tt);
obb.invokeT();
AppDomain app1 = AppDomain.CreateDomain("newdom");
NS22.testappdom ob2 = (NS22.testappdom)app1.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, typeof(NS22.testappdom).FullName,
false, BindingFlags.Default, null, new object[] { tt }, null, null, null);
ob2.invokeT();
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
public bool testingg (Object obj) {
Console.WriteLine("testingg called..");
return false;
}
}
}
namespace NS22 {
class testappdom : MarshalByRefObject {
public delegate bool MYDelT(Object obj);
public MYDelT delee;
public testappdom() {
Console.WriteLine("Init.");
}
public testappdom(MYDelT dd) {
Console.WriteLine("Init1.");
this.delee = dd;
}
public void invokeT() {
this.delee(new Object());
}
}
}

Related

Is it possible to get the name of the object being instantiated, from within the constructor?

Is there any way, using reflection, ConstructorInfo or System.Runtime.CompilerServices or something else, to get the variable name of the object being created?
Example:
public class MyObject
{
public MyObject()
{
// Should print "Creating funnyName"
Debug.Writeline("Creating {0}", MagicGetNameMethod());
}
}
public class MyClass
{
public MyObject funnyName = null;
public void MyMethod()
{
funnyName = new MyObject();
}
}
You can get the file path, line number and method name of the caller, which is probably more useful for timing info:
The following will print something like Creating MyMethod#c:\source\MyProgram.cs:15.
public class MyObject
{
public MyObject(
[CallerMemberName]string caller = null,
[CallerFilePathAttribute] string path = null,
[CallerLineNumber]int lineNumber = 0)
{
Console.WriteLine("Creating {0}", $"{caller}#{path}:{lineNumber}");
System.Reflection.
MethodBase.GetCurrentMethod();
}
}
public class MyClass
{
public MyObject funnyName = null;
public void MyMethod()
{
funnyName = new MyObject();
}
}

Calling a private function from another class in C#

I have a program called Scenario2_Client.xaml.cs that has the following function:
namespace SDKTemplate
{
public sealed partial class Scenario2_Client : Page
{
private MainPage rootPage = MainPage.Current;
// code
// this is the function I would like to call
private void RemoveValueChangedHandler()
{
ValueChangedSubscribeToggle.Content = "Subscribe to value changes";
if (subscribedForNotifications)
{
registeredCharacteristic.ValueChanged -= Characteristic_ValueChanged;
registeredCharacteristic = null;
subscribedForNotifications = false;
}
}
// ...
}
}
And then I have added a class in a different file (but in the same project) called EchoClient.cs which has the following code:
namespace SDKTemplate
{
class EchoClient
{
public void TcpClient()
{
try
{
TcpClient client = new TcpClient("139.169.63.130", 9999);
StreamReader reader = new StreamReader(client.GetStream());
StreamWriter writer = new StreamWriter(client.GetStream());
string s = string.Empty;
while (!s.Equals("Exit"))
{
Console.WriteLine("TCP Client connected....");
Console.WriteLine("Enter a string or number to send to the server: ");
s = Console.ReadLine();
writer.WriteLine(s);
writer.Flush();
string server_string = reader.ReadLine();
Console.WriteLine(server_string);
}
reader.Dispose();
writer.Dispose();
client.Dispose();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
internal class Console
{
internal static string ReadLine()
{
throw new NotImplementedException();
}
internal static void WriteLine(string v)
{
throw new NotImplementedException();
}
internal static void WriteLine(Exception e)
{
throw new NotImplementedException();
}
internal class TcpClient
{
private string v1;
private int v2;
public TcpClient(string v1, int v2)
{
this.v1 = v1;
this.v2 = v2;
}
internal void Dispose()
{
throw new NotImplementedException();
}
internal Stream GetStream()
{
throw new NotImplementedException();
}
}
}
Is there a way to call that function from this class?
I would have done something like this if it was public:
EchoClient client = new EchoClient()
client.somefunction();
client.somefunction();
..but since this method is private, how should I access it?
It is possible to invoke a private method using reflection as follows.
var iMethod
= client.GetType().GetMethod("somefunction",
BindingFlags.NonPublic | BindingFlags.Instance);
iMethod.Invoke(client, new object[]{});
I'm not sure why #Codor was down-voted, but here's the same answer fleshed out a little more. First I create a class with a private method:
public class PrivateFunction
{
private int _age;
public PrivateFunction(int age)
{
_age = age;
}
private int DoSomethingPrivate(string parameter)
{
Debug.WriteLine($"Parameter: {parameter}, Age: {_age}");
return _age;
}
}
I created a method that takes parameters and returns an integer to show all possibilities.
Then I call it:
var type = typeof(PrivateFunction);
var func = type.GetMethod("DoSomethingPrivate", BindingFlags.Instance | BindingFlags.NonPublic);
var obj = new PrivateFunction(12);
var ret = func.Invoke(obj, new[] {"some parameter"});
Debug.WriteLine($"Function returned {ret}");
and I get this in the output (proving something happened):
Parameter: some parameter, Age: 12
Function returned 12
If you are going to repeatedly call the same function (perhaps with different objects), save the MethodInfo object in func. It's immutable and re-useable.

How to create a exception handling and logging class in C#

I am working on a small project, I am trying to create a layer that will handle exception and logging.
This layer will sit in between User interface and DAL, mostly like BAL which will have some generic method that will then initiate further call to Data access layer.
Some thing like this
Public Class ExceptionHandler
{
//which should take a method name,parameters and return a object.
Public T InitiateDatabaseCall(//method name as input,parameters)
{
try
{
//then make the call to the method using the input parameter and pass the parameters
}
catch(Exception e)
{
// do logging
}
}
This layer will act as center repository to handle and log exception. I am not able to create the method that i described can experts provide some snippet that will show case this scenario.
Edited: With code added
static void Main(string[] args)
{
BAL b = new BAL();
var ll = b.GetFieldList("xxxxyyyy");
}
public class BAL
{
public List<Fields> GetFieldList(string screen)
{
if(!string.IsNullOrEmpty(screen))
{
ExceptionHandler.InitiateCall(() =>GetList(screen) ));
}
}
}
public static class ExceptionHandler
{
public T InitiateCall<T>(Func<T>method,object[] parms) where T : object
{
try
{
return method.Invoke();
}
catch(Exception ex)
{
return default(T);
}
}
}
public class DAL
{
public List<Fields> GetList(string name)
{
VipreDBDevEntities context = new VipreDBDevEntities();
return context.Database.SqlQuery<Fields>("SCREEN_FIELDS_SELECT #SCREEN_NAME", name).ToList();
}
}
It gives error GetList() does not exist in current context.
For these kind of things AOP (Aspect Oriented Programming, see https://en.wikipedia.org/wiki/Aspect-oriented_programming) is a really good fit.
These are cross-cutting concerns that are cluttering code if not done properly.
See for an example AOP framework PostSharp. Even with the free version that is simple to code. There are also (might be paid) build-in aspects for that, like http://doc.postsharp.net/exception-tracing.
A simple alternative is using a Func or Action (try it out in a Console App):
static void Main(string[] args)
{
ExceptionHandler.InitiateDatabaseCall(() => CallDb("Dummy"));
ExceptionHandler.InitiateDatabaseCall<int>(() => { throw new InvalidOperationException(); });
}
int CallDb(string justToShowExampleWithParameters)
{
return 5;
}
public static class ExceptionHandler
{
public static T InitiateDatabaseCall<T>(Func<T> method)
{
try
{
return method.Invoke();
}
catch (Exception e)
{
// do logging
Console.WriteLine(e.Message);
return default(T); // or `throw` to pass the exception to the caller
}
}
}
Edit:
based on your added code in the question you can solve the error about GetList() by some minor modifications:
static void Main(string[] args) {
BAL b = new BAL();
var ll = b.GetFieldList("xxxxyyyy");
}
public class BAL
{
public List<Fields> GetFieldList(string screen)
{
if (!string.IsNullOrEmpty(screen))
{
return ExceptionHandler.InitiateCall(() => new DAL().GetList(screen)); // Slight modification of your code here
}
else
{
return null; // or whatever fits your needs
}
}
}
public class ExceptionHandler
{
public static T InitiateCall<T>(Func<T> method)
{
try
{
return method.Invoke();
}
catch (Exception ex)
{
//log
return default(T);
}
}
}
public class DAL
{
public List<Fields> GetList(string name)
{
VipreDBDevEntities context = new VipreDBDevEntities();
return context.Database.SqlQuery<Fields>("SCREEN_FIELDS_SELECT #SCREEN_NAME", name).ToList();
}
}
You don't need the object[] parms parameter in InitiateCall given the provided code. Any paramaters you need for the method call are given in the Func<T>
Personally, I think loging should be done in two ways:
Step logging (when you log some step in your code)
Scope logging (when you log begin/end of some code or it's time)
So, I always choose to create ILogger class with these two ways:
public sealed class Logger : ILogger
{
private readonly Serilog.ILogger _seriLogger;
public Logger(Serilog.ILogger seriLogger)
{
_seriLogger = seriLogger;
}
public void Debug(string format, params object[] args)
{
_seriLogger.Debug(format, args);
}
public void Info(string format, params object[] args)
{
_seriLogger.Information(format, args);
}
public void Warn(string format, params object[] args)
{
_seriLogger.Warning(format, args);
}
public void Error(Exception e, string format, params object[] args)
{
_seriLogger.Error(e, format, args);
}
public void Fatal(Exception e, string format, params object[] args)
{
_seriLogger.Fatal(e, format, args);
}
public IDisposable GetScope(string name, long timeout = 0)
{
return new LoggerScope(this, name, timeout);
}
}
internal class LoggerScope : IDisposable
{
private readonly ILogger _logger;
private readonly string _name;
private readonly long _timeout;
private readonly Stopwatch _sw;
private bool ExceedScope
{
get { return _timeout > 0; }
}
public LoggerScope(ILogger logger, string name, long timeout)
{
_logger = logger;
_name = name;
_timeout = timeout;
if (!ExceedScope)
{
_logger.Debug("Start execution of {0}.", name);
}
_sw = Stopwatch.StartNew();
}
public void Dispose()
{
_sw.Stop();
if (ExceedScope)
{
if (_sw.ElapsedMilliseconds >= (long)_timeout)
{
_logger.Debug("Exceeded execution of {0}. Expected: {1}ms; Actual: {2}ms.", _name, _timeout.ToString("N"), _sw.Elapsed.TotalMilliseconds.ToString("N"));
}
}
else
{
_logger.Debug("Finish execution of {0}. Elapsed: {1}ms", _name, _sw.Elapsed.TotalMilliseconds.ToString("N"));
}
}
}
Then, If I want to log something, I use it like this, without AOP:
using(_log.GetScope("Some describable name"))
{
//Some code here
}

Get static List from AppDomain

I want to get access to a static List of Class2, which will be created in Class1.
Class1 is loaded in an AppDomain and loads Class2 in an other AppDomain.
But if I want to get access to the static List in Class2, I get two different Lists.
I think I have to access to the same AppDomain in Class1 to get Class2, but how I can achieve this, if the objects of Class1 are in different AppDomains?
By the way: It is not neccessary to put Class2 in an other AppDomain, but I thought I could get the same object if I would do it.
Here is my code:
public class Class1 : MarshalByRefObject
{
Class2 class2;
public Class2 Class2
{
get { return class2; }
set { class2 = value; }
}
public Class1()
{
AppDomain adc2 = AppDomain.CreateDomain("adc2");
class2 = (Class2)adc2.CreateInstanceAndUnwrap(typeof(Class2).Assembly.FullName, typeof(Class2).FullName);
}
}
public class Class2 : MarshalByRefObject
{
static List<int> myIntegers = new List<int>();
public static List<int> MyIntegers
{
get { return Class2.myIntegers; }
set { Class2.myIntegers = value; }
}
public void AddInteger(int integer)
{
myIntegers.Add(integer);
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (int integer in myIntegers)
{
sb.AppendLine(integer.ToString());
}
return sb.ToString();
}
}
class Program
{
static void Main(string[] args)
{
Type type1 = typeof(Class1);
AppDomain ad1 = AppDomain.CreateDomain("ad1");
Class1 ad1t1 = (Class1)ad1.CreateInstanceFromAndUnwrap(type1.Assembly.Location, type1.FullName);
AppDomain ad2 = AppDomain.CreateDomain("ad2");
Class1 ad2t1 = (Class1)ad2.CreateInstanceFromAndUnwrap(type1.Assembly.Location, type1.FullName);
ad1t1.Class2.AddInteger(0);
ad2t1.Class2.AddInteger(1);
Console.WriteLine(ad1t1.Class2.ToString()); //Output: 0
Console.WriteLine(ad2t1.Class2.ToString()); //Output: 1
//
Console.ReadKey();
}
}
Edit
Ok I found out that my plugin loader is to blame.
Can someone say why you cant work across appdomains if you will use different Pluginloaders (or at least one loader)?
If all files are in one Assembly it will work (increment is 3). In my scenario (many different assemblies) I only get 1,1,1
If someone need more information to help me, feel free to ask for it.
Example 1 (Each Instance count for itself):
Assembly: Main
PluginLoader.PluginLoader<IPlugin> pluginLoader1 = new PluginLoader.PluginLoader<IPlugin>(new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)));
IPlugin cl1 = pluginLoader1.Activate("MyLibrary.dll", "MyLibrary.Class1");
PluginLoader.PluginLoader<IPlugin> pluginLoader2 = new PluginLoader.PluginLoader<IPlugin>(new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)));
IPlugin cl3 = pluginLoader2.Activate("MyLibrary2.dll", "MyLibrary2.Class3");
//Increment() increases a static variable starting by 0
cl1.Increment();
Console.WriteLine(cl1.ToString()); //Output: 1
cl3.Increment();
Console.WriteLine(cl3.ToString()); //Output: 1
ClassLibrary2.Class2 class2 = new ClassLibrary2.Class2();
class2.Increment();
Console.WriteLine(class2.ToString()); //Output: 1
Assembly: ClassLibrary2
[Serializable]
public class Class2 : IPlugin
{
public Class2() { }
public override string ToString()
{
return incrementer.ToString();
}
static int incrementer = 0;
public void Increment()
{
incrementer++;
}
}
Assembly: MyLibrary
public class Class1 : MarshalByRefObject, IPlugin
{
Class2 class2;
public Class2 Class2
{
get { return class2; }
set { class2 = value; }
}
public Class1()
{
PluginLoader.PluginLoader<Class2> pluginLoader = new PluginLoader.PluginLoader<Class2>(new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)));
class2 = pluginLoader.Activate("ClassLibrary2.dll", "ClassLibrary2.Class2");
//AppDomain adc2 = AppDomain.CreateDomain("adc2");
//class2 = (Class2)adc2.CreateInstanceAndUnwrap(typeof(Class2).Assembly.FullName, typeof(Class2).FullName);
}
public void Increment()
{
this.class2.Increment();
}
public override string ToString()
{
return AppDomain.CurrentDomain.FriendlyName+": "+ this.class2.ToString();
}
}
Assembly: MyLibrary2
public class Class3 : MarshalByRefObject, IPlugin
{
Class2 class2;
public Class2 Class2
{
get { return class2; }
set { class2 = value; }
}
public Class3()
{
PluginLoader.PluginLoader<Class2> pluginLoader = new PluginLoader.PluginLoader<Class2>(new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)));
class2 = pluginLoader.Activate("ClassLibrary2.dll", "ClassLibrary2.Class2");
//AppDomain adc2 = AppDomain.CreateDomain("adc2");
//class2 = (Class2)adc2.CreateInstanceAndUnwrap(typeof(Class2).Assembly.FullName, typeof(Class2).FullName);
}
public void Increment()
{
this.class2.Increment();
}
public override string ToString()
{
return AppDomain.CurrentDomain.FriendlyName + ": " + this.class2.ToString();
}
}
Assembly: PluginInterface
public interface IPlugin
{
void Increment();
}
Assembly: PluginLoader
public class PluginLoader<T> where T : IPlugin
{
//Here are placed all Fields
#region Fields
string path;
System.AppDomain appDomain;
#endregion
//Here are placed all Properties
#region Properties
public List<KeyValuePair<String, String>> Plugins
{
get { return (List<KeyValuePair<String, String>>)appDomain.GetData("Plugins"); }
}
#endregion
//Here are placed all Constructors
#region Constructors
public PluginLoader(DirectoryInfo path)
{
this.path = path.FullName;
if (!path.Exists)
path.Create();
AppDomainSetup appDomainSetup = new AppDomainSetup();
appDomainSetup.AppDomainInitializer = new AppDomainInitializer(GetInterfaceTypes);
appDomainSetup.AppDomainInitializerArguments = new string[] { this.path };
appDomain = AppDomain.CreateDomain(typeof(T).Name, null, appDomainSetup);
}
#endregion
#region Methods
private static void GetInterfaceTypes(string[] args)
{
AppDomain appDomain = System.AppDomain.CurrentDomain;
string[] files = Directory.GetFiles(args[0], "*.dll", SearchOption.AllDirectories);
List<KeyValuePair<String, String>> infos = new List<KeyValuePair<String, String>>();
foreach (string file in files)
{
try
{
Assembly asm = Assembly.LoadFrom(file);
foreach (Type type in asm.GetTypes())
{
if (typeof(T).IsAssignableFrom(type))
infos.Add(new KeyValuePair<string, string>(file, type.FullName));
}
}
catch (Exception ex)
{
}
}
appDomain.SetData("Plugins", infos);
}
public virtual T Activate(String assemblyFile, String type, params object[] args)
{
try
{
T instance = (T)this.appDomain.CreateInstanceFromAndUnwrap(Path.Combine(this.path, Path.GetFileName(assemblyFile)), type, args);
return instance;
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
}
Example 2 (Each instance count the same increment variable):
Put all classes in one assembly.
public interface IPlugin
{
void Increment();
}
[Serializable]
public class Class1 : IPlugin
{
public Class1() { }
static int incrementer = 0;
public void Increment()
{
incrementer++;
}
public override string ToString()
{
return incrementer.ToString();
}
}
class PluginLoader<T> where T : IPlugin
{
//Here are placed all Fields
#region Fields
string path;
System.AppDomain appDomain;
#endregion
//Here are placed all Properties
#region Properties
public List<KeyValuePair<String, String>> Plugins
{
get { return (List<KeyValuePair<String, String>>)appDomain.GetData("Plugins"); }
}
#endregion
//Here are placed all Constructors
#region Constructors
public PluginLoader(DirectoryInfo path)
{
this.path = path.FullName;
if (!path.Exists)
path.Create();
AppDomainSetup appDomainSetup = new AppDomainSetup();
appDomainSetup.AppDomainInitializer = new AppDomainInitializer(GetInterfaceTypes);
appDomainSetup.AppDomainInitializerArguments = new string[] { this.path };
appDomain = AppDomain.CreateDomain(typeof(T).Name, null, appDomainSetup);
}
#endregion
#region Methods
private static void GetInterfaceTypes(string[] args)
{
AppDomain appDomain = System.AppDomain.CurrentDomain;
string[] files = Directory.GetFiles(args[0], "*.dll", SearchOption.AllDirectories);
List<KeyValuePair<String, String>> infos = new List<KeyValuePair<String, String>>();
foreach (string file in files)
{
try
{
Assembly asm = Assembly.LoadFrom(file);
foreach (Type type in asm.GetTypes())
{
if (typeof(T).IsAssignableFrom(type))
infos.Add(new KeyValuePair<string, string>(file, type.FullName));
}
}
catch (Exception ex)
{
}
}
appDomain.SetData("Plugins", infos);
}
public virtual T Activate(String assemblyFile, String type, params object[] args)
{
try
{
T instance = (T)this.appDomain.CreateInstanceFromAndUnwrap(Path.Combine(this.path, Path.GetFileName(assemblyFile)), type, args);
return instance;
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
}
class Program
{
static void Main(string[] args)
{
string file = System.Reflection.Assembly.GetExecutingAssembly().Location;
string path = Path.GetDirectoryName(file);
PluginLoader<IPlugin> pluginLoader1 = new PluginLoader<IPlugin>(new DirectoryInfo(path));
IPlugin cl1 = pluginLoader1.Activate(file, "AppDomainCheck.Class1");
PluginLoader<IPlugin> pluginLoader2 = new PluginLoader<IPlugin>(new DirectoryInfo(path));
IPlugin cl3 = pluginLoader1.Activate(file, "AppDomainCheck.Class1");
cl1.Increment();
Console.WriteLine(cl1.ToString()); //Output: 1
cl3.Increment();
Console.WriteLine(cl3.ToString()); //Output: 2
Console.ReadKey();
}
}
Static variables are limited to the current App domain. If you have N different app domains, then you have N different values for a static property.
In C# Language Specification 5.0 :
10.5.1 A static field is not part of a specific instance; instead, it is shared amongst all instances of a closed type (ยง4.4.2). No matter how many instances of a closed class type are created, there is only ever one copy of a static field for the associated application domain.

After creating an instance how to cast it to the created type

say I have a method that returns a type:
private Type GetPersonOrOrganisation(someParameter)
{
either return Person type or Organisation type
}
Then I call this method:
Type type = GetPersonOrOrganisation(someParameter);
I then try to create a new instance of the returned type:
var newContact = Activator.CreateInstance(type);
What I'm left with is that newContact is of type object. What I wanted was newContact to be of either type Person or Organisation depending on what was returned from GetPersonOrOrganisation.
Does anyone know how to get the newContact cast to the correct type?
This definitely has some code smell to it. But there are perhaps some ways around it.
You might want to consider an interface that both person and organization implement if you are going to interact with them the same way. Or maybe a base class, depending on your specific scenario.
Beyond that, we probably need what you're trying to do afterwards to be able to give suggestions. Without the interface (or some other base class), you can't have ONE object that can be either of those types. The only thing they have in common currently is object.
You could do some different things like if (newContact is Person) { } else if (newContact is Organisation) { } or similar depending on your scenario, but that's really getting into the code smell unless you're absolutely stuck with those objects and methods the way they are.
You can return an initialized object from the function and test it using GetType() and typeof. Below is one example (certainly Tim's example will work as well).
public class Person
{
}
public class Organization
{
}
class Program
{
// Generate a Person if i == true or Organization if i == false
static object GetPersonOrOrganization(bool i)
{
if (i == true)
{
return new Person();
}
else
{
return new Organization();
}
}
static void Main(string[] args)
{
var p = GetPersonOrOrganization(true); // Generates a Person.
if (p.GetType() == typeof(Person))
{
Console.WriteLine("Person!"); // This prints.
}
else
{
Console.WriteLine("Organization");
}
var o = GetPersonOrOrganization(false); // Generates an Organization.
if (o.GetType() == typeof(Person))
{
Console.WriteLine("Person!");
}
else
{
Console.WriteLine("Organization!"); // This prints.
}
Console.ReadLine();
}
}
You need somethign like this:
public interface IPersonOrganization {
}
public class Peron : IPersonOrganization {
}
public class Organization : IPersonOrganization {
}
private IPersonOrganization GetPersonOrganization(bool isPerson) {
if (isPerson)
return new Person();
else
return new Organization;
}
Here's one way; though this assumes a parameterless constructor exists:
using System;
namespace StackOverflow.Demos
{
class Program
{
public static void Main(string[] args)
{
new Program();
Console.ReadKey();
}
private Program()
{
Type type = GetPersonOrOrganisation(new Person());
//object myInstance = GetInstanceOfType(type);
var myInstance = GetInstanceOfType(type);
Console.WriteLine(myInstance.ToString());
type = GetPersonOrOrganisation(new Organization());
myInstance = GetInstanceOfType(type);
Console.WriteLine(myInstance.ToString());
}
private Type GetPersonOrOrganisation(object what)
{
return what.GetType();
}
private object GetInstanceOfType(Type type)
{
//return type.GetConstructor(new Type[] { }).Invoke(new object[] { });
return Activator.CreateInstance(type);
}
}
public class Person
{
public Person() { }
}
public class Organization
{
public Organization() { }
}
}
Is this the issue you're having?
public void Demo()
{
var myInstance = Activator.CreateInstance((new Person()).GetType());
Console.WriteLine(Test(myInstance));
}
private string Test(object x) //this is the method being called
{
return string.Format("Object - {0}", x.ToString());
}
private string Test(Person x) //this is what you were hoping for
{
return string.Format("Person - {0}", x.ToString());
}
private string Test(Organization x)
{
return string.Format("Org - {0}", x.ToString());
}
One fix is this (not recommended):
public void Demo()
{
var myInstance = Activator.CreateInstance((new Person()).GetType());
Console.WriteLine(Test(myInstance));
}
private string Test(object x) //redirect the call to the right method
{
if (x is Person)
return Test(x as Person);
else
return Test(x as Organization);
}
private string Test(Person x) { return string.Format("Person - {0}", x.ToString()); } //this is what you were hoping for
private string Test(Organization x) { return string.Format("Org - {0}", x.ToString()); }
A better solution is this:
public interface ITestMethod { string Test();}
public class Person : ITestMethod
{
public Person() { }
public string Test() { return string.Format("Person - {0}", this.ToString()); }
}
public class Organization : ITestMethod
{
public Organization() { }
public string Test() { return string.Format("Org - {0}", this.ToString()); }
}
//...
public void Demo()
{
var myInstance = Activator.CreateInstance((new Person()).GetType()) as ITestMethod;
Console.WriteLine(myInstance.Test());
}
//...

Categories

Resources