使用变量创建和对象并将其传递给其他类

时间:2015-12-10 22:02:32

标签: c#

我试图在代码示例中尽可能好地解释它,我不确定我想要的是一种还是另一种方式。

以下代码确实有效,但我无法传递null值,而且我无法更改'对象'中的值。在我创建它之后。 如何创建可以执行此操作的variableTable对象?

public static void SomeMethod(string variableOne, int variableTwo, UInt64 variableThree)
    {
        //create an object that contains variables for this specific method
        //there are more methods like this 'SomeMethod' that have diferent variables and more or less variables
        //this 'VariableHandler' reads and modifies the values via reflection and needs to be able to be used on onther methods
        //also the variables can be null and this is not possible with an anonymous types
        var variableTable = new { variableOne = variableOne, variableTwo = variableTwo, variableThree = variableThree }; //create an anomymous type with the variables

        using (VariableHandler handler = new VariableHandler(variableTable)) //check and modify the variables via reflection
        {
            Console.WriteLine(variableTable.variableOne);       //do  somthing with the checked and modified methods
            Console.WriteLine(variableTable.variableTwo);
            Console.WriteLine(variableTable.variableThree);

        }
    }

3 个答案:

答案 0 :(得分:1)

根据MSDN(here),匿名类型的属性是只读的 - 所以当然您无法更改它们。它还声明您无法将属性初始化为null。

为什么会这样 - 您必须向微软询问或阅读文章 - 可能还有更多内容供您使用。

如果您希望能够更改属性或将它们初始化为null,则需要创建一个非匿名对象。

答案 1 :(得分:1)

也许您想为每个变量使用一个小对象,例如:

public interface IVariableValue { }

public class VariableValue<T> : IVariableValue
{
    public T Value { get; set; }

    public VariableValue(T value) { Value = value; }

    public override ToString() { return Value.ToString(); }
}

接口是必需的,因为您需要一些常用类型来存储在字典中。它是一个空白的界面,因为我无法定义T Value属性,也不会使界面通用并遇到在同一个字典中有多个泛型类型的相同问题。

然后,使用Dictionary

而不是匿名类型
public static void SomeMethod(string variableOne, int variableTwo, UInt64 variableThree)
{
    var variableTable = new Dictionary<string, IVariableValue>()
        {
            ["variableOne"] = new VariableValue<string>(variableOne),
            ["variableTwo"] = new VariableValue<int>(variableTwo),
            ["variableThree"] = new VariableValue<UInt64>(variableThree),
        };

    using (VariableHandler handler = new VariableHandler(variableTable))
    {
        Console.WriteLine(variableTable["variableOne"]);
        Console.WriteLine(variableTable["variableTwo"]);
        Console.WriteLine(variableTable["variableThree"]);
    }
}

注意字典初始化程序是C#6的一项功能,如果您不是在C#6上,那么在您之后,您必须.Add到字典创造它。

VariableHandler可以在构造函数中使用Dictionary<string, IVariableValue>的参数:

public class VariableHandler : IDisposable
{
    //IDisposable implementation not shown, but required for using

    public VariableHandler(Dictionary<string, IVariableValue> variables)
    {
        //You can do whatever you want here using reflection
    }
}

答案 2 :(得分:0)

虽然罗恩的答案符合你的需要,但我认为它可以用一种不那么冗长的方式解决。

如果参数名称不是特别重要,但能够将参数作为一个包传递,修改它们并使用它们再次调用一个方法,那么也许一个具有可写属性的Tuple类就足够了:

public static class Arguments
{
    // This convenience method enables type-inference, so the generic types
    // don't need to be supplied (which is necessary when calling the
    // Arguments<T1, T2, T3> constructor):
    public static Arguments<T1, T2, T3> Create<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3)
    {
        return new Arguments<T1, T2, T3>(arg1, arg2, arg3);
    }
}

public class Arguments<T1, T2, T3>
{
    public T1 Argument1 { get; set; }
    public T2 Argument2 { get; set; }
    public T3 Argument3 { get; set; }

    public Arguments(T1 arg1, T2 arg2, T3 arg3)
    {
        Argument1 = arg1;
        Argument2 = arg2;
        Argument3 = arg3;
    }
}

这可以用作以下内容:

public static void SomeMethod(string variableOne, int variableTwo, UInt64 variableThree)
{
    var arguments = Arguments.Create(variableOne, variableTwo, variableThree);

    Console.WriteLine(arguments.Argument1);
    Console.WriteLine(arguments.Argument2);
    Console.WriteLine(arguments.Argument3);
}

您必须为必须支持的每个 number 参数创建单独的类和便捷方法,类似于不同数量的项目有不同的Tuple类。< / p>

参数名称

如果确实需要保留参数名称,以便可以编写arguments.variableOne而不进行动态处理,那么您将必须为每个方法编写一个类。此时,您也可以修改这些方法以接受这样的对象作为单个参数。

如果在运行时需要参数名称,可以使用反射来获取有关调用方法的信息。要可靠地这样做可能会非常棘手 - 正如Ron所指出的那样,一些方法(如strack-trace检查或调用MethodBase.GetCurrentMethod)将面向方法内联失败。

直接传递对方法的引用应该有效:

public class Arguments
{
    public static Arguments<T1, T2, T3> Create<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
    {
        return new Arguments<T1, T2, T3>(action, arg1, arg2, arg3);
    }
}

public class Arguments<T1, T2, T3>
{
    public Argument<T1> Argument1 { get; set; }
    public Argument<T2> Argument2 { get; set; }
    public Argument<T3> Argument3 { get; set; }


    public Arguments(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
    {
        var methodInfo = action.GetMethodInfo();
        var parameters = methodInfo.GetParameters();

        Argument1 = new Argument<T1>(parameters[0].Name, arg1);
        Argument2 = new Argument<T2>(parameters[1].Name, arg2);
        Argument3 = new Argument<T3>(parameters[2].Name, arg3);
    }
}

// A wrapper class to hold both the name and value of a parameter/argument:
public class Argument<T>
{
    public string Name { get; private set; }
    public T Value { get; set; }


    public Argument(string name, T value)
    {
        Name = name;
        Value = value;
    }
}

用法更改为:

public static void SomeMethod(string variableOne, int variableTwo, UInt64 variableThree)
{
    var arguments = Arguments.Create(SomeMethod, variableOne, variableTwo, variableThree).Dump();

    Console.WriteLine(arguments.Argument1.Name + " = " + arguments.Argument1.Value);
    Console.WriteLine(arguments.Argument2.Name + " = " + arguments.Argument2.Value);
    Console.WriteLine(arguments.Argument3.Name + " = " + arguments.Argument3.Value);
}