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

本文关键字:其他 变量 创建 对象 | 更新日期: 2023-09-27 18:26:20

我已经在代码示例中尽可能好地解释了它,我不确定我想要的是以某种方式实现的。

下面的代码确实有效,但我无法传递null值,并且在创建"object"后也无法更改该值。我如何创建一个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);
        }
    }

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

也许你想为每个单独的变量使用一个小对象,比如:

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#上,则必须在创建字典后将其.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
    }
}

根据MSDN(此处),匿名类型的属性是只读的,因此您当然不能更改它们。它还声明不能将属性初始化为null。

为什么——你必须问微软,或者阅读这篇文章——可能会有更多适合你的东西。

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

虽然Ron的答案满足了您的需要,但我认为它可以用一种不那么冗长的方式来解决。

如果参数名称不是特别重要,但能够将参数作为捆绑包传递、修改它们并使用它们再次调用方法,那么也许一个具有可写属性的类似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);
}

您必须为必须支持的每个数量的参数创建一个单独的类和方便方法,类似于不同数量的项有不同的Tuple类。

参数名称

如果您确实需要保留参数名称,以便在不动态的情况下编写arguments.variableOne,那么您必须为每个方法编写一个类。在这一点上,您还可以修改这些方法,以接受这样一个对象作为单个参数。

如果在运行时需要参数名称,可以使用反射来获取有关调用方法的信息。要可靠地做到这一点可能很棘手——正如Ron所指出的,strack跟踪检查或调用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);
}