How to get instances of a class using Reflection? - c#

How to get instances of a class using C# Reflection?.
For example,
public class Sample
{
}
Sample s = new Sample();
Sample s2 = new Sample();
Sample s3 = new Sample();
How to get these three instances of sample class using reflection?

Using System.Activator.CreateInstance you can create instances of a class using reflection. For example...
System.Type type = typeof(Sample);
object obj = Activator.CreateInstance(type);
In this example obj is your newly created instance. There's few overloads of this method, more information in this MSDN Documentation
Edit Based On Comment
If what you want is to be able to retrieve all instances of a class, I guess this is not possible using managed code. You will need to use unmanaged code to either profile the managed heap using the Profiling API or use the HeapWalk function to enumerating all objects allocated in the managed heap.

var s = (Sample)Activator.CreateInstance(Sample);
var s2 = (Sample)Activator.CreateInstance(Sample);
var s3 = (Sample)Activator.CreateInstance(Sample);

Related

Sparx EA.App doesn't reflect Activator.CreateInstance properly

I've got .NET Framework 4.6.2 console app that is accessing Sparx Enterprise Architect repository. The code below shows a simple example of using Activator.CreateInstance(). The problem is that when creating a second instance the current one (stored in eaApp) is used, so I cannot access two different repositories. Is there any witted solution to this problem?
static void Main(string[] args)
{
EA.App eaApp = (EA.App)Activator.CreateInstance(Type.GetTypeFromProgID("EA.App", true));
EA.App eaApp2 = (EA.App)Activator.CreateInstance(Type.GetTypeFromProgID("EA.App", true));
eaApp.Repository.OpenFile(#"c:\Temp\UCI2.EAP");
eaApp2.Repository.OpenFile(#"c:\Temp\UCI3.EAP");
EA.Element test = eaApp.Repository.GetElementByGuid("{53F2ADAE-E8AC-40da-A06F-D64F525B87E8}");
EA.Element test2 = eaApp2.Repository.GetElementByGuid("{DBF0459F-0662-4e5b-B7E3-A065087B624E}");
Console.WriteLine($"test1: {test.Notes} test2: {test2.Notes}");
Console.ReadKey();
}
If you want to create a new instance do something like this
EA.Repository r = new EA.Repository();
r.OpenFile("c:\\eatest.eap");
As described in the manual
Connecting to the (first) running instance can be done like this:
using System.Runtime.InteropServices;
...
object obj = Marshal.GetActiveObject("EA.App");
var eaApp = obj as EA.App;
var myRepository = eaApp?.Repository;

Create an object with method using c# reflection

I have a problem where I need to create a tfs version control server object using reflection after loading the dll in c#. I'm having trouble initializing it in reflection however as it has no constructors. Without reflection you normally create the object using the getService method in a team project collection object. Here is my code:
namespace SendFiletoTFS
{
class Program
{
static void Main(string[] args)
{
String tfsuri = #"uri";
NetworkCredential cred = new NetworkCredential("user", "password", "domain");
// Load in the assemblies Microsoft.TeamFoundation.Client.dll and Microsoft.TeamFoundation.VersionControl.Client.dll
Assembly tfsclient = Assembly.LoadFrom(#"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Client.dll");
Assembly versioncontrol = Assembly.LoadFrom(#"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.VersionControl.Client.dll");
// Create Team Project Collection
Type tpcclass = tfsclient.GetType(#"Microsoft.TeamFoundation.Client.TfsTeamProjectCollection");
// The 'getService' method.
MethodInfo getService = tpcclass.GetMethods()[32];
object tpc = Activator.CreateInstance(tpcclass, new object[] { new Uri(tfsuri), cred });
Type VersionControlServerClass = versioncontrol.GetType(#"Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer");
// Code I'm trying to emulate in reflection, this is how I would normally do it without reflection.
//VersionControlServer versionControl = tpc.GetService<VersionControlServer>();
// Create VersionControlServer Class. This line will not work and give a no constructor found exception.
object vcs = Activator.CreateInstance(VersionControlServerClass, new object[] { tpc });
//How do I create the vcs object ?
}
}
}
Is there some way I can create this version control server object using the getService method in the team project collection class?
Any help would be greatly appreciated.
You can call the method this way:
var closedMethod = getService.MakeGenericMethod(VersionControlServerClass);
object vcs = closedMethod.Invoke(tpc, null);
As a note, you should not use something like tpcclass.GetMethods()[32]; because reflection does not guarantee you the order of the returned methods. Better use GetMethod([methodname]);
Note the TfsTeamProjectCollection implements IServiceProvider, which actually has non-generic version of GetService:
object vcs = ((IServiceProvider)tpc).GetService(VersionControlServerClass);

Using application's *.resx from a generic DLL

I'm creating a generic DLL that creates documents from models and can be used either for winForms or for webForms. It's composed of a main class that I instantiate with certain parameters.
I'd like my DLL to be able to lookup in the resource files without being tied down to 1 technology.
So to say, I know how to access my resource files (*.resx) in a WebForm :
HttpContext.GetGlobalResourceObject("Global", "myLabel")
I have a few restrictions :
I don't want to transfer the HttpContext to the DLL as it will tie it to the application
I don't want to rename the resource files from *.resx to *.resource because they are used in the application
I don't want to pass all the labels over to the DLL because then my models won't be modifiable as I need
I'd like to place a marker in my document models that is like this <%resource(Global,myLabel)%>
I've been looking at passing the class a resource object using ResourceManager but it never gets hold of my *.resx files.
Does anyone know how to acheive the final goal? Either passing a resource object to the class either picking up the resource object from inside the class.
Ok, I found how to do this.
In my DLL, I overloaded the constructor allowing to give it a ResourceManagerobject. So here is what I have :
For the model file :
\paragraph
[
Style = "Normal"
]
{
<%resource(lblMontant)%> : <%montant%>
}
For the DLL using the ResourceManager :
public Reporter(String inputModel, String outputPdf, Dictionary<String, IParameter> parameters, ResourceManager resman)
{
// Assigne parameters to globals
_sourceFile = inputModel;
_destinationFile = outputPdf;
_parameters = parameters;
_rm = resman;
Worker();
}
private String parseResource(String val)
{
MatchCollection _matches = _resourceMatcher.Matches(val);
foreach (Match _match in _matches)
{
String _item = _match.Groups["item"].Value;
val = val.Replace(_match.Groups[0].Value, String.Format("{0}", _rm.GetObject(_item)));
}
return val;
}
For the caller, we use Resources.global that is considered a class :
ResourceManager _rm = new ResourceManager(typeof(Resources.global));
Reporter _cl = new Reporter(modelFilePath, outputFilePath, _params, _rm);
If this is useful to others and some need more details, don't hesitate to ask ;)

c# create an instance of an object from string

I have a string variable contain:
string classCode = "public class Person { public string Name{get;set;} }";
How can I create an instance of an object from the classCode ?
like
object obj = CreateAnInstanceAnObject(classCode);
You'll need to use CodeDom to compile an in-memory assembly, and then use reflection to create the type.
Here's a sample article on MSDN that walks through the process of code generation.
Once you've compiled the code, you can use Activator.CreateInstance to create an instance of it.
Building on the answers from above, here is a working demo to generate, compile and instantiate a class from an in-memory assembly:
namespace DynamicCompilation
{
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
internal static class Program
{
private static void Main()
{
var ccu = new CodeCompileUnit();
var cns = new CodeNamespace("Aesop.Demo");
cns.Imports.Add(new CodeNamespaceImport("System"));
var ctd = new CodeTypeDeclaration("Test")
{
TypeAttributes = TypeAttributes.Public
};
var ctre = new CodeTypeReferenceExpression("Console");
var cmie = new CodeMethodInvokeExpression(ctre, "WriteLine", new CodePrimitiveExpression("Hello World!"));
var cmm = new CodeMemberMethod
{
Name = "Hello",
Attributes = MemberAttributes.Public
};
cmm.Statements.Add(cmie);
ctd.Members.Add(cmm);
cns.Types.Add(ctd);
ccu.Namespaces.Add(cns);
var provider = new CSharpCodeProvider();
var parameters = new CompilerParameters
{
CompilerOptions = "/target:library /optimize",
GenerateExecutable = false,
GenerateInMemory = true
};
////parameters.ReferencedAssemblies.Add("System.dll");
var results = provider.CompileAssemblyFromDom(parameters, ccu);
if (results.Errors.Count == 0)
{
var t = results.CompiledAssembly.GetType("Aesop.Demo.Test");
var inst = results.CompiledAssembly.CreateInstance("Aesop.Demo.Test");
t.InvokeMember("Hello", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, inst, null);
}
Console.ReadLine();
}
}
}
Simple put you cannot do this in one line as you are attempting. It is possible to create an instance of an existing class via it's name and one of the overloads of Activator.CreateInstance.
What you are trying to achieve here though is quite different. You are attempting to both 1) define a new class type and 2) create an instance of it. Defining new metadata in the running process dynamically is very difficult to achieve with static languages like C#. It requires a significant amount of work that can't easily be put into a StackOverflow answer.
The following project should guide you in what your trying to accomplish:
RunTime Code Compilation
However, if you are attempting to write code at runtime, you may want to rethink your architecture. You may be creating more of a headache for yourself than you need to be.
What are you trying to accomplish by creating this object?

Is it possible to serialize a C# code block?

I'm using C# with .NET 3.5. Is it possible to serialize a block of code, transmit it somewhere, deserialize it, and then execute it?
An example usage of this would be:
Action<object> pauxPublish = delegate(object o)
{
if (!(o is string))
{
return;
}
Console.WriteLine(o.ToString());
};
Transmitter.Send(pauxPublish);
With some remote program doing:
var action = Transmitter.Recieve();
action("hello world");
My end goal is to be able to execute arbitrary code in a different process (which has no prior knowledge of the code).
YES!!!
We have done this for a very real case of performance. Doing this at runtime or using a DSL was not an option due to performance.
We compile the code into an assembly, and rip the IL out of the method. We then get all the metadata associated with this method and serialize the whole mess via XML, compress it, and put it in our database.
At re-hydration time, we re-constitute the IL with the metadata using the DynamicMethod class, and execute it.
We do this because of speed. We have thousands of little blocks of code. Unfortunately, to compile a block of code and run it on the fly takes at least 250 ms, which is way too slow for us. We took this approach, and it is working REALLY well. At run-time, it takes an unmeasurable amount of time to reconstitute the method and run it.
Only thing to keep an eye on... Signed assemblies and Unsigned assemblies cannot mix the serialized method data.
You could try to use IronPython in your project. It's trivial to do what you are asking in Python. The Python code could call your C# methods. As for security, you could execute the code in a restricted environment of some kind (one example is RestrictedPython).
Generally speaking that sounds like a really bad idea and a big security hole.
You don't want another process to execute any code. Understand what you really need another process to do and build a little DSL around it.
You could also send it as a string then use the CodeDomProvider to compile it, same result. I have an example bit of code thus:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.CSharp;
namespace DynamicCodeApplication
{
class azCodeCompiler
{
private List<string> assemblies;
public azCodeCompiler()
{
assemblies = new List<string>();
scanAndCacheAssemblies();
}
public Assembly BuildAssembly(string code)
{
CodeDomProvider prov = CodeDomProvider.CreateProvider("CSharp");
string[] references = new string[] { }; // Intentionally empty, using csc.rsp
CompilerParameters cp = new CompilerParameters(references)
{
GenerateExecutable = false,
GenerateInMemory = true
};
string path = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
cp.CompilerOptions = "#" + path + #"\csc.rsp";
CompilerResults cr = prov.CompileAssemblyFromSource(cp, code);
foreach (CompilerError err in cr.Errors)
{
Console.WriteLine(err.ToString());
}
return cr.CompiledAssembly;
}
public object ExecuteCode(string code,
string namespacename, string classname,
string functionname, bool isstatic, params object[] args)
{
object returnval = null;
Assembly asm = BuildAssembly(code);
object instance = null;
Type type = null;
if (isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
MethodInfo method = type.GetMethod(functionname);
returnval = method.Invoke(instance, args);
return returnval;
}
private void scanAndCacheAssemblies()
{
/*
foreach (string str in Directory.GetFiles(#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727"))
{
if (str.Contains(".dll"))
{
foreach (string st in str.Split(new char[] { '\\' }))
{
if (st.Contains(".dll"))
{
assemblies.Add(st);
}
}
}
}
* */
assemblies.Add("Accessibility.dll");
assemblies.Add("AspNetMMCExt.dll");
assemblies.Add("cscompmgd.dll");
assemblies.Add("CustomMarshalers.dll");
assemblies.Add("IEExecRemote.dll");
assemblies.Add("IEHost.dll");
assemblies.Add("IIEHost.dll");
assemblies.Add("Microsoft.Build.Conversion.dll");
assemblies.Add("Microsoft.Build.Engine.dll");
assemblies.Add("Microsoft.Build.Framework.dll");
assemblies.Add("Microsoft.Build.Tasks.dll");
assemblies.Add("Microsoft.Build.Utilities.dll");
assemblies.Add("Microsoft.Build.VisualJSharp.dll");
assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll");
assemblies.Add("Microsoft.JScript.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.dll");
assemblies.Add("Microsoft.VisualBasic.dll");
assemblies.Add("Microsoft.VisualBasic.Vsa.dll");
assemblies.Add("Microsoft.Vsa.dll");
assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll");
assemblies.Add("Microsoft_VsaVb.dll");
assemblies.Add("mscorlib.dll");
assemblies.Add("sysglobl.dll");
assemblies.Add("System.configuration.dll");
assemblies.Add("System.Configuration.Install.dll");
assemblies.Add("System.Data.dll");
assemblies.Add("System.Data.OracleClient.dll");
assemblies.Add("System.Data.SqlXml.dll");
assemblies.Add("System.Deployment.dll");
assemblies.Add("System.Design.dll");
assemblies.Add("System.DirectoryServices.dll");
assemblies.Add("System.DirectoryServices.Protocols.dll");
assemblies.Add("System.dll");
assemblies.Add("System.Drawing.Design.dll");
assemblies.Add("System.Drawing.dll");
assemblies.Add("System.EnterpriseServices.dll");
assemblies.Add("System.Management.dll");
assemblies.Add("System.Messaging.dll");
assemblies.Add("System.Runtime.Remoting.dll");
assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll");
assemblies.Add("System.Security.dll");
assemblies.Add("System.ServiceProcess.dll");
assemblies.Add("System.Transactions.dll");
assemblies.Add("System.Web.dll");
assemblies.Add("System.Web.Mobile.dll");
assemblies.Add("System.Web.RegularExpressions.dll");
assemblies.Add("System.Web.Services.dll");
assemblies.Add("System.Windows.Forms.dll");
assemblies.Add("System.XML.dll");
assemblies.Add("vjscor.dll");
assemblies.Add("vjsjbc.dll");
assemblies.Add("vjslib.dll");
assemblies.Add("vjslibcw.dll");
assemblies.Add("vjssupuilib.dll");
assemblies.Add("vjsvwaux.dll");
assemblies.Add("vjswfc.dll");
assemblies.Add("VJSWfcBrowserStubLib.dll");
assemblies.Add("vjswfccw.dll");
assemblies.Add("vjswfchtml.dll");
assemblies.Add("Accessibility.dll");
assemblies.Add("AspNetMMCExt.dll");
assemblies.Add("cscompmgd.dll");
assemblies.Add("CustomMarshalers.dll");
assemblies.Add("IEExecRemote.dll");
assemblies.Add("IEHost.dll");
assemblies.Add("IIEHost.dll");
assemblies.Add("Microsoft.Build.Conversion.dll");
assemblies.Add("Microsoft.Build.Engine.dll");
assemblies.Add("Microsoft.Build.Framework.dll");
assemblies.Add("Microsoft.Build.Tasks.dll");
assemblies.Add("Microsoft.Build.Utilities.dll");
assemblies.Add("Microsoft.Build.VisualJSharp.dll");
assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll");
assemblies.Add("Microsoft.JScript.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.dll");
assemblies.Add("Microsoft.VisualBasic.dll");
assemblies.Add("Microsoft.VisualBasic.Vsa.dll");
assemblies.Add("Microsoft.Vsa.dll");
assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll");
assemblies.Add("Microsoft_VsaVb.dll");
assemblies.Add("mscorlib.dll");
assemblies.Add("sysglobl.dll");
assemblies.Add("System.configuration.dll");
assemblies.Add("System.Configuration.Install.dll");
assemblies.Add("System.Data.dll");
assemblies.Add("System.Data.OracleClient.dll");
assemblies.Add("System.Data.SqlXml.dll");
assemblies.Add("System.Deployment.dll");
assemblies.Add("System.Design.dll");
assemblies.Add("System.DirectoryServices.dll");
assemblies.Add("System.DirectoryServices.Protocols.dll");
assemblies.Add("System.dll");
assemblies.Add("System.Drawing.Design.dll");
assemblies.Add("System.Drawing.dll");
assemblies.Add("System.EnterpriseServices.dll");
assemblies.Add("System.Management.dll");
assemblies.Add("System.Messaging.dll");
assemblies.Add("System.Runtime.Remoting.dll");
assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll");
assemblies.Add("System.Security.dll");
assemblies.Add("System.ServiceProcess.dll");
assemblies.Add("System.Transactions.dll");
assemblies.Add("System.Web.dll");
assemblies.Add("System.Web.Mobile.dll");
assemblies.Add("System.Web.RegularExpressions.dll");
assemblies.Add("System.Web.Services.dll");
assemblies.Add("System.Windows.Forms.dll");
assemblies.Add("System.XML.dll");
assemblies.Add("vjscor.dll");
assemblies.Add("vjsjbc.dll");
assemblies.Add("vjslib.dll");
assemblies.Add("vjslibcw.dll");
assemblies.Add("vjssupuilib.dll");
assemblies.Add("vjsvwaux.dll");
assemblies.Add("vjswfc.dll");
assemblies.Add("VJSWfcBrowserStubLib.dll");
assemblies.Add("vjswfccw.dll");
assemblies.Add("vjswfchtml.dll");
return;
}
}
}
Compile it into a separate assembly, send the assembly, have the other process load it.
You might want to consider security implications.
Update: another idea would be to generate an expression tree and use this library to serialize it:
http://www.codeplex.com/metalinq/
It is an interesting challenge, but you should probably describe why you want to do this, since there is a lot of different approaches depending on your objective. As humpohl points out, there is also some pretty serious security issues.
"Serialized code" could just be source code or a compiled assembly, depending on your requirements. You probably don't need to use a seperate code serialization format.
If you want to generate code dynamically and pass that on, you could generate code using CodeDOM and compile it. However, you most likely dont need to generate completely arbitrary code.
Another option is using the DLR, and constraining the code to execute...

Categories