【问题标题】:MSBuild: Describe Which Constructor to CallMSBuild:描述要调用的构造函数
【发布时间】:2013-02-04 12:09:53
【问题描述】:

我正在处理需要实例化类的 MSBuild 任务。该类最初只有一个无参数构造函数,因此所需要的所有 MSBuild 任务就是实例化该类的类型名称。现在我们有一个为特定构造函数运行任务的用例,我不知道如何以通用方式处理它。假设我需要实例化不同风格的ClassA

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>

我不知道要搜索什么才能获得这种功能。我可以做一些事情,比如创建一个名为ConstructorArgs 的字符串属性并使用我想要的任何格式对其进行解析,但我希望存在更清晰的东西。感谢您提供的任何帮助!

编辑 - 如果有人想知道,我尝试修改的 实际 任务会创建一个基于实例化实体框架 DbContext 的预生成视图。我们有自己的 DbContext 子类和各种构造函数,我们希望能够在视图生成期间调用特定的构造函数。

【问题讨论】:

    标签: c# .net msbuild msbuild-task


    【解决方案1】:

    您可以尝试 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>
    

    希望这会有所帮助。

    【讨论】:

    • 这与我在任务中实际执行的操作类似,但我试图解决的问题涉及未知数量的各种类型的参数。所以我可能有这样的构造函数:(string,int,int),(string,bool),(string,bool,bool)。我更多的是寻找如何在 MSBuild 中提供具有原始类型描述符的字符串数组。
    猜你喜欢
    • 1970-01-01
    • 2021-03-09
    • 2013-06-12
    • 1970-01-01
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多