MSBuild: describe which constructor to call

I am working with an MSBuild task that is supposed to instantiate a class. Initially, the class had only one constructor without parameters, therefore, to complete the entire MSBuild task, there was a type name for instantiating the class. Now we have a precedent for launching a task for specific designers, and I do not know how to deal with this in a general way. Let's say I need to create different variants of ClassA :

 public class ClassA { public ClassA() { } public ClassA(int someArgument) { } public ClassA(int someArgument, bool someOtherArgument) { } } 

Here's what the original task looked like:

 <DoSomethingTask Assembly="ContainsClassA.dll" Type="ClassA" /> 

My ideal task would look something like this so that I could call any constructor with primitive types as arguments:

 <DoSomethingTask Assembly="ContainsClassA.dll" Type="ClassA"> <ConstructorArgs> <Arg type="int">1</Arg> <Arg type="bool">True</Arg> </ConstructorArgs> </DoSomethingTask> 

I really lost what to look for to get this type of functionality. I could do something like create a string property ConstructorArgs and parse it in whatever format I want, but I hope something cleaner exists. Thanks for any help you can provide!

Change In case someone wonders, the actual task I am trying to modify creates a pre-generated view based on an instance of the Entity Framework DbContext. We have our own subclass of DbContext with various constructors, and we would like to be able to call a specific one when generating a view.

+4
source share
1 answer

You can try to use reflection and get a constructor for your subclass of DBContext.

 using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace TaskClass { // Class to be created public class MyDbContext { public int ConstructorArg1 { get; set; } public string ConstructorArg2 { get; set; } public MyDbContext() { } public MyDbContext(int constructorArg1) { ConstructorArg1 = constructorArg1; } public MyDbContext(int constructorArg1, string constructorArg2) { ConstructorArg1 = constructorArg1; ConstructorArg2 = constructorArg2; } } // MSBuild custom task public class DoSomethingTask : Task { public override bool Execute() { var taskParameters = new TaskParametersInfo(); taskParameters.ExtractTaskParametersInfo(this); var type = typeof(MyDbContext); ConstructorInfo ctor = type.GetConstructor(taskParameters.Types.ToArray()); if (ctor == null) { // If the constructor is not found, throw an error Log.LogError("There are no constructors defined with these parameters."); return false; } // Create your instance var myDbContext = (MyDbContext)ctor.Invoke(taskParameters.Values.ToArray()); return true; } public int ConstructorArg1 { get; set; } public string ConstructorArg2 { get; set; } public string ConstructorArg3 { get; set; } // Class to handle the task parameters internal class TaskParametersInfo { public List<Type> Types { get; set; } public List<object> Values { get; set; } public TaskParametersInfo() { Types = new List<Type>(); Values = new List<object>(); } public void ExtractTaskParametersInfo(Task task) { foreach (var property in task.GetType().GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance)) { var propertyValue = property.GetValue(task, null); if (propertyValue != null) { Types.Add(property.PropertyType); Values.Add(propertyValue); } } } } } } 

Import the task into the msbuild project:

 <?xml version="1.0" encoding="UTF-8" standalone="no" ?> <Project ToolsVersion="4.0" defaultTarget="DoSomething" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <UsingTask TaskName="TaskClass.DoSomethingTask" AssemblyFile="TaskClass\TaskClass\bin\Debug\TaskClass.dll"/> <Target Name="DoSomething"> <DoSomethingTask ConstructorArg1="123" ConstructorArg2="Are u talking to me?" /> </Target> </Project> 

Hope this helps.

0
source

All Articles