2013-02-19 2 views
4

Я работаю с задачей MSBuild, которая должна создавать экземпляр класса. Первоначально у класса был только один конструктор без параметров, поэтому для выполнения всей задачи MSBuild было имя типа для создания экземпляра класса. Теперь у нас есть прецедент для запуска задачи для конкретных конструкторов, и я не знаю, как справиться с этим в общем виде. Скажем, мне нужно создать экземпляр различные ароматы из ClassA:MSBuild: Опишите, какой конструктор для вызова

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

Это то, что исходная задача выглядела как:

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

Мой идеал задача будет выглядеть примерно так, чтобы я мог вызвать любой конструктор, который имеет примитивный типы в качестве аргументов:

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

Я очень потерял, что искать, чтобы получить этот тип функциональности. Я мог бы сделать что-то вроде создания свойства string, которое называется ConstructorArgs, и проанализировать его в любом формате, который я хочу, но я надеюсь, что что-то более чистое. Спасибо за любую помощь, которую вы можете предоставить!

Редактировать - В случае, если кто-либо задается вопросом, действительный Задача, которую я пытаюсь изменить, создает прегенерированный вид на основе созданной Entity Framework DbContext. У нас есть свой собственный подкласс DbContext с различными конструкторами, и мы хотели бы иметь возможность вызывать конкретный во время генерации представления.

ответ

0

Вы можете попробовать use reflection and get a constructor для вашего подкласса 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's 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); 
        } 
       } 
      } 
     } 
    } 
} 

Импорт задача на вашем MSBuild проекте:

<?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> 

Надеется, что это помогает.

+0

Это похоже на то, что я действительно делал бы в задаче, но проблема, которую я пытаюсь решить, включает неизвестное количество аргументов разных типов. Поэтому у меня могут быть такие конструкторы, как: (string, int, int), (string, bool), (string, bool, bool). Я больше искал, как предоставить массив в строках MSBuild с дескриптором примитивного типа. – Ocelot20