有没有一种方法可以创建托管类型变量的通过引用列表?

时间:2020-04-13 17:57:26

标签: c# data-structures pass-by-reference

编辑;根据答复,我的最终目标可能还不清楚。我已经更新了最后一部分。

情况

我有很多变量需要执行相同的操作。在这种情况下,它们是strings,并且在我们到达此代码时可以具有值null"""Blank",或者它们可以已经分配了其他值。我想保留的价值。

if (String.IsNullOrEmpty(MyVar1) || "Blank".Equals(MyVar1))
    MyVar1 = null;
if(String.IsNullOrEmpty(MyVar2) || "Blank".Equals(MyVar2))
    MyVar2 = null;
...
if(String.IsNullOrEmpty(MyVar10) || "Blank".Equals(MyVar10))
    MyVar10 = null;

作为一名程序员,我希望保持我的代码整洁,并且此块使我发疯,我正在寻找一种方法来创建这些变量的列表,并对每个变量执行相同的if语句+空赋值。

例如,这是我想做的:

MyVar1 = "Blank";
DreamDataStructure varList = new DreamDataStructure() { MyVar1, MyVar2, ..., MyVar10 };
foreach(ref string MyVar in varList)
{
    if(String.IsNullOrEmpty(MyVar) || "Blank".Equals(MyVar))
        MyVar = null;
}
Console.WriteLine(MyVar1); //Should now be null

什么不起作用

1)因为我的变量是strings,所以我不能做这样的事情。

var myListOfVariables = new[] { &MyVar1, &MyVar2, ..., &MyVar10 };

如果可以的话,我可以按预期foreach覆盖它们。由于string是托管类型,因此无法像这样通过引用传递。

2)同样,如果我只是对变量进行List<string>,它们将按值传递,对我的情况无济于事。

3)这些变量不能包装在外部对象类型中,因为它们需要在旧版应用程序的许多地方用作字符串。假设要更改每个位置的用法将花费很大的精力。

问题

是否有一种通过引用传递方式遍历string(或其他托管类型)变量的方法,该方法将使我可以将整个操作放入循环内并减少重复的代码发生在这里吗?

这里的目标是我以后可以在代码中使用原始变量和更新后的值。稍后将由遗留代码引用MyVar1等,这些遗留代码希望它们为null或具有实际值。

4 个答案:

答案 0 :(得分:1)

如果我正确理解了您的问题,我认为您想做的事是不可能的。请参阅以下问题:Interesting "params of ref" feature, any workarounds?

我唯一能建议的(我知道并不能回答您的问题)是创建一种避免条件逻辑重复的方法:

void Convert(ref string text)
{
    if (string.IsNullOrEmpty(text) || "Blank".Equals(text))
    {
        text = null;
    }
}

答案 1 :(得分:0)

更新:

现在,我明白了您要做什么。您有一堆变量,并且想要对它们执行某种批量操作而不更改其他任何内容。不能将它们放在课程中。

在这种情况下,您真的很难一次操作它们。有一些方法可以缩短它,但是您对重复的工作非常执着。

我会

  • 创建一个string SanitizeString(string input)函数
  • 为每个变量键入一次x = SanitizeString(x);
  • 复制并粘贴变量名称以替换x

很me脚,但仅此而已。


也许这是一个更好的方法。它确保始终对值进行清理。否则,您将无法轻易分辨出这些值是否已经过消毒:

public class MyValues
{
    private string _value1;
    private string _value2;
    private string _value3;

    public string Value1
    {
        get { return _value1; }
        set { _value1 = Sanitize(value); }
    }

    // repeat for other values

    private string Sanitize(string input) =>
        string.IsNullOrEmpty(input) || string.Equals("Blank", input) ? null : input;
}

那是一个选择。另一个是更早地清理输入。但理想情况下,我们要确保给定的类始终处于有效状态。无论值是否有效,我们都不希望有一个类的实例。最好确保它们始终有效。

ref并没有真正纳入其中。如果有的话,我们不需要经常使用它。使用值类型或string,我们可以从函数中返回新值。

如果我们要传递引用类型,并且想要对其进行更改(例如设置其属性,将项目添加到列表中),那么我们已经传递了引用,我们不需要指定{{1 }}。

我会尝试先编写方法而不使用ref,只有在需要时才使用它。您可能永远不会,因为如果不使用ref,您将成功完成任何尝试做的事情。


您的评论提到这是一个旧版应用程序,最好不要修改现有类。剩下的另一个选择是反射。不是我的最爱,但是当您说“旧版应用程序”时,我会感到很痛苦。在这种情况下,您可以这样做:

ref

这将获取一个对象,找到其字符串属性,并对其进行清理。它将按类型将字符串属性存储在字典中,这样,一旦发现给定类型的字符串属性,就无需再次执行该操作。

public static class StringSanitizer
{
    private static Dictionary<Type, IEnumerable<PropertyInfo>> _stringProperties = new Dictionary<Type, IEnumerable<PropertyInfo>>();

    public static void SanitizeStringProperties<T>(T input) where T : class
    {
        if (!_stringProperties.ContainsKey(typeof(T)))
        {
            _stringProperties.Add(typeof(T), GetStringProperties(typeof(T)));
        }

        foreach (var property in _stringProperties[typeof(T)])
        {
            property.SetValue(input, Sanitize((string)property.GetValue(input)));
        }
    }

    private static string Sanitize(string input)
    {
        return string.IsNullOrEmpty(input) || string.Equals("Blank", input) ? null : input;
    }

    private static IEnumerable<PropertyInfo> GetStringProperties(Type type)
    {
        return type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(property => property.PropertyType == typeof(string) && property.CanRead && property.CanWrite);
    }
}

答案 2 :(得分:0)

您可以创建一个函数而不是传递引用,这也将更具可读性。

string Validate(string inputString)
{
   return string.IsNullOrEmpty(inputString) || "Blank".Equals(inputString) ? null : inputString;
}

<...>
 MyVar1 = Validate(MyVar1);

答案 3 :(得分:-1)

您可以简单地使用string []并将更改返回给调用方方法,像这样。

public Main()
{
    var myVar1 = "Blank";
    var myVar2 = "";
    string myVar3 = null;
    var myVar4 = "";
    string[] dreamDataStructure = new string[] { myVar1, myVar2, myVar3, myVar4 };
}

private void ProcessStrings(string[] list)
{
    for(int i = 0; i < list.Length; i++)
    {

        if (String.IsNullOrEmpty(list[i]) || "Blank".Equals(list[i]))
            list[i] = null;
    }
}