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);
Related
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;
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm writing a program that would have the possibility to learn for itself.
Example:
a word 'day' was typed
look for interface named 'day'
does it exists?
No => create class based on that interface (and implement the interface) and save it for next use then create instance of that class
Yes => create instance of that class
Google gave me this: How to dynamically create a class in C#?
This solution is the closest I can think of for my scenario, but it assumes you already know how many properties you will need and doesn't implement an interface at all.
I have no experience at all with system.reflection but I'm eager to learn!
Anyone know an example for my case?
Any help is appriciated.
Thank You!
EDIT: MY SOLUTION
(Because nobody gave me a straight answer I figured it out myself)
public void createObject(string name)
{
//Namespace where the interfaces are located
string strnamespace = "Intelligence.Omnia.Categories";
//Get interfacecollection
List<Type> interfaceCollection = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsInterface && t.Namespace == strnamespace).ToList();
foreach (Type myinterface in interfaceCollection)
{
//interface names
List<string> interfaceNames = new List<string>();
if (myinterface.Name == name)
{
//Add interface name
interfaceNames.Add(myinterface.Name);
//Add current interfaceproperties
List<PropertyInfo> myProps = myinterface.GetProperties().ToList();
//Does the current interface inhiretes from other interfaces?
foreach (Type inhiretences in myinterface.GetInterfaces())
{
//Add interface name
interfaceNames.Add(inhiretences.Name);
//Add those properties aswell!
foreach (PropertyInfo pi in inhiretences.GetProperties())
{
myProps.Add(pi);
}
}
createType(name, myProps, interfaceNames);
}
}
}
static void createType(string name, List<PropertyInfo> props, List<string> interfacesnames)
{
//create instance of CSharpCodeProvider
CSharpCodeProvider csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
//DLL
string pathDLL = AppDomain.CurrentDomain.BaseDirectory + "Objects.dll";
CompilerParameters parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.dll", "System.Linq.dll", "System.Threading.Tasks.dll", "Intelligence.dll" });
parameters.OutputAssembly = pathDLL;
parameters.GenerateExecutable = false;
ICodeCompiler icc = csc.CreateCompiler();
//>>>>Generated CODE
//Add namespaces
CodeCompileUnit compileUnit = new CodeCompileUnit();
CodeNamespace ns = new CodeNamespace("Objects");
compileUnit.Namespaces.Add(ns);
ns.Imports.Add(new CodeNamespaceImport("System"));
ns.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
ns.Imports.Add(new CodeNamespaceImport("System.Linq"));
ns.Imports.Add(new CodeNamespaceImport("System.Text"));
ns.Imports.Add(new CodeNamespaceImport("System.Threading.Tasks"));
ns.Imports.Add(new CodeNamespaceImport("Intelligence"));
ns.Imports.Add(new CodeNamespaceImport("Intelligence.Omnia"));
ns.Imports.Add(new CodeNamespaceImport("Intelligence.Omnia.Categories"));
//Define your class
CodeTypeDeclaration classType = new CodeTypeDeclaration("Object"+name);
classType.Attributes = MemberAttributes.Public; //make it public
foreach(string interfaceName in interfacesnames) //let it inherit from the interfaces
{
classType.BaseTypes.Add(interfaceName);
}
ns.Types.Add(classType);
//Add constructor
CodeConstructor constr = new CodeConstructor();
constr.Attributes = MemberAttributes.Public;
classType.Members.Add(constr);
//Add all the properties
foreach (var prop in props)
{
//If you want private fields
//CodeMemberField field = new CodeMemberField(prop.PropertyType, prop.Name);
//classType.Members.Add(field);
CodeMemberProperty property = new CodeMemberProperty();
property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
property.Type = new CodeTypeReference(prop.PropertyType);
property.Name = prop.Name;
property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), prop.Name)));
property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), prop.Name), new CodePropertySetValueReferenceExpression()));
classType.Members.Add(property);
}
//Write the file for later use
TextWriter tw = new StreamWriter(new FileStream(AppDomain.CurrentDomain.BaseDirectory + "Objects\\" + name + ".cs", FileMode.Create));
csc.GenerateCodeFromCompileUnit(compileUnit, tw, null);
tw.Close();
//Compile the class
CompilerResults results = icc.CompileAssemblyFromFile(parameters, AppDomain.CurrentDomain.BaseDirectory + "Objects\\" + name + ".cs");
results.Errors.Cast<CompilerError>().ToList().ForEach(error => System.Windows.Forms.MessageBox.Show(error.ErrorText));
}
As #Stefan says you can dynamically create type using the DLR built into .net 4.0+ but you can also use the older reflection based mechanism in CodeDom. My suggestion is to look at IronPython as this can do what you want really easily. However if you want C#, then you need to understand that C# is compiled and you need to use the compilation in System.CodeDom.Compiler.
Nothing can infer knowledge from word Day to what the interface Day is - you have to supply this is some way. However if you know the rules by which the interface will exist, you can create it dynamically. You can also go further and create additional types based on the interface. Again no code can be written magically - you need to supply the code semantics and syntax.
However if you have this you could separate the code into multiple assemblies (CompileAssemblyFromSource). Then dynamically load the assemblies to load the types (step 2). You can create types and assemblies at runtime (see OS: Generating DLL assembly dynamically at run time).
This code is from the above linked SO answer, and shows you how to an assembly from some string of code.
using System.CodeDom.Compiler;
using System.Diagnostics;
using Microsoft.CSharp;
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.OutputAssembly = "My_Assembly_Day.dll";
CompilerResults results = icc.CompileAssemblyFromSource(parameters, ".... some C# code ....");
This SO answer shows you how to load assemblies to discover types:
https://stackoverflow.com/a/14184863/30225
edit: To answer comments.
You can name your assembly anything you like - my suggestion is to name it with interface/class combination. The above is just an example of how you can name it
You can either load the existing (pre created assemblies) at load time (first step in the program), or you can dynamically load the assemblies at runtime when needed.
Once you've loaded the assemblies the types are available to you (Activator.CreateInstance) for example.
If you get to your step and for instance type IDay is not available, you can dynamically create it using type text. Of course to get the CodeDom compiler to work, you'll need to ensure that all the things that this code references is supplied to the compilation unit. And compile that into an assembly on the disk. You can create the interface & the class that same time or in two steps.
Once step 4 is done you can load that assembly like in step 3 & 4.
at the end of the day the answer boils down to:
Find the existing type from existing types set
If existing type is not available create it in an assembly dynamically.
Load that type
Instantiate that type.
The concern comes when using that type. You can either create more code using CodeDom (in effect this gives you the ability to recreate classes that may already exist BTW) or you can use types dynamically in your code. The first has the compilation overhead, while the second has the complexity in writing code that doesn't have hard coded types - a job made very simple btw using the C# dynamic keyword. Either way this is a very run of the mill .net coding technique when using types dynamically, and many existing applications use techniques like this for managing plugins.
Caveat:
Please remember that the smallest unloadable unit in .net is the AppDomain. When you load assemblies you load them into an AppDomain. If you want unload assemblies (and thus types) to replace them fo instance, you need to unlaod the AppDomain. This means that you need to ensure that any dynamically loaded assemblies are loaded into new AppDomains which in turn can be unloaded when needed.
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);
I'm trying to create a Windows Form Application, that can create another Windows Form Application. But the error i'm getting when i'm trying to compile with CodeDom in the c# code, is a weird one.
'kjpUnityGameLauncherTemplate.RunLauncher' does not have a suitable static Main method
This kinda confuses me, since the class "RunLauncher" DOES have a main method, with the default setup described at the (http://msdn.microsoft.com/) site.
RunLauncher class: http://pastebin.com/NU3VYwpv (which have the main method)
The code i'm using to actually compile this via. CodeDom is this:
if (codeProvider.Supports(GeneratorSupport.EntryPointMethod))
{
parameters.MainClass = "kjpUnityGameLauncherTemplate.RunLauncher";
}
CodeCompileUnit compileUnits = new CodeCompileUnit();
CodeNamespace nsp = new CodeNamespace("kjpUnityGameLauncherTemplate");
parameters.CompilerOptions = "/main:kjpUnityGameLauncherTemplate.RunLauncher";
CodeTypeDeclaration class1 = new CodeTypeDeclaration("RunLauncher");
nsp.Types.Add(class1);
CodeTypeDeclaration class2 = new CodeTypeDeclaration("kjpUnityGameLauncher");
nsp.Types.Add(class2);
CodeTypeDeclaration class3 = new CodeTypeDeclaration("Launcher");
nsp.Types.Add(class3);
nsp.Imports.Add(new CodeNamespaceImport("kjpUnityGameLauncherTemplate"));
compileUnits.Namespaces.Add(nsp);
CompilerResults results = icc.CompileAssemblyFromDom(parameters, compileUnits);
Theres some other stuff like declaration of the variables "codeProvider" etc. but those aren't the problem in this case, which is why I didn't include them.
To Create an Executable Your code must have an Entry Point Method declared and set properly to run in CodeDom. I do not see one declared in your example above. Below I have an example from MSDN located at
http://msdn.microsoft.com/en-us/library/y2k85ax6.aspx
CodeEntryPointMethod start = new CodeEntryPointMethod();
CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression("System.Console"),
"WriteLine", new CodePrimitiveExpression("Hello World!"));
start.Statements.Add(cs1);
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?