简体   繁体   中英

How to find a reference to an array by the name of the variable as defined in the code in C#?

Obviously, I'm not looking for the classic:

string[] garden = {"Tulip"};
Console.WriteLine(garden[0]);

but rather, doing the same with a string:

string[] garden = {"Tulip"};
string gardenname = "garden";
string[] cool_NEW_array = ArrayByName(gardenname);
Console.WriteLine(cool_NEW_array[0])

I'm curious as to whether there is some actually existing version of "ArrayByName" which would let me find an array by using a string which is its name. Thanks in advance!

It is impossible, as I know, and this may cause lots of problems about reflexion and generated IL.

There is the nameof operator and meanings to get variables names in the caller of a method, but it is not intended for your goal.

Perhaps there some reflection tools to do that, but I don't know.

Perhaps you can do that using huge reflexion on a whole assembly by parsing all classes, all instances, all fields and properties members, all methods and all local vars of these methods...

In all case, you may encounter problems with duplicates vocabulary.

But you can use a Dictionary keyed by the name of the intended variable name.

Thus you create a sort of data table.

We use a class variable as private to store some one-dimension string arrays and public methods to add and remove these arrays from the collection as well as a method to find which can match having one string using Contains (or equality if you want).

The collection

static private readonly Dictionary<string, string[]> RegisteredArrays 
  = new Dictionary<string, string[]>();

The register and unbregister methods

static public void RegisterArray(string name, string[] array)
{
  if ( !RegisteredArrays.ContainsKey(name)
    && !RegisteredArrays.ContainsValue(array) )
    RegisteredArrays.Add(name, array);
}

static public void UnregisterArray(string name)
{
  if ( RegisteredArrays.ContainsKey(name) )
    RegisteredArrays.Remove(name);
}

static public void UnregisterArray(string[] array)
{
  if ( RegisteredArrays.ContainsValue(array) )
  {
    var item = RegisteredArrays.FirstOrDefault(kvp => kvp.Value == array).Key;
    RegisteredArrays.Remove(item);
  }
}

The find method

static public IEnumerable<string[]> FindRegisteredArray(string name)
{
  foreach ( var item in RegisteredArrays )
    if ( item.Key == name )
      yield return item.Value;
}

Test

static void Test()
{
  string[] garden1 = { "Tulip", "Rose" };
  string[] garden2 = { "Flower 1", "Flower 2", "Flower 3" };

  RegisterArray(nameof(garden1), garden1);
  RegisterArray(nameof(garden2), garden2);

  string gardenname = "garden1";

  foreach ( var array in FindRegisteredArray(gardenname) )
    Console.WriteLine(string.Join(",", array));

  foreach ( var array in FindRegisteredArray("garden2") )
    Console.WriteLine(string.Join(",", array));
}

Output

Tulip,Rose
Flower 1,Flower 2,Flower 3

Improvements

You can create a whole class to offer the desired behavior

static public class NamedStringArrayManager
{
  static private readonly Dictionary<string, string[]> RegisteredArrays
    = new Dictionary<string, string[]>();

  static public void Register(string name, string[] array)
  {
    if ( !RegisteredArrays.ContainsKey(name)
      && !RegisteredArrays.ContainsValue(array) )
      RegisteredArrays.Add(name, array);
  }

  static public void Unregister(string name)
  {
    if ( RegisteredArrays.ContainsKey(name) )
      RegisteredArrays.Remove(name);
  }

  static public void Unregister(string[] array)
  {
    if ( RegisteredArrays.ContainsValue(array) )
    {
      var item = RegisteredArrays.FirstOrDefault(kvp => kvp.Value == array).Key;
      RegisteredArrays.Remove(item);
    }
  }

  static public IEnumerable<string[]> Find(string name)
  {
    foreach ( var item in RegisteredArrays )
      if ( item.Key == name )
        yield return item.Value;
  }
}
static void Test()
{
  string[] garden1 = { "Tulip", "Rose" };
  string[] garden2 = { "Flower 1", "Flower 2", "Flower 3" };

  NamedStringArrayManager.Register(nameof(garden1), garden1);
  NamedStringArrayManager.Register(nameof(garden2), garden2);

  string gardenname = "garden1";

  foreach ( var array in NamedStringArrayManager.Find(gardenname) )
    Console.WriteLine(string.Join(",", array));

  foreach ( var array in NamedStringArrayManager.Find("garden2") )
    Console.WriteLine(string.Join(",", array));
}

We can also create a generic manager for any type

static public class NamedInstanceManager<T>
{
  static private readonly Dictionary<string, T> RegisteredArrays
    = new Dictionary<string, T>();

  static public void Register(string name, T instance)
  {
    if ( !RegisteredArrays.ContainsKey(name)
      && !RegisteredArrays.ContainsValue(instance) )
      RegisteredArrays.Add(name, instance);
  }

  static public void Unregister(string name)
  {
    if ( RegisteredArrays.ContainsKey(name) )
      RegisteredArrays.Remove(name);
  }

  static public void Unregister(T instance)
  {
    if ( RegisteredArrays.ContainsValue(instance) )
    {
      var item = RegisteredArrays.FirstOrDefault(kvp => kvp.Value.Equals(instance)).Key;
      RegisteredArrays.Remove(item);
    }
  }

  static public IEnumerable<T> Find(string name)
  {
    foreach ( var item in RegisteredArrays )
      if ( item.Key == name )
        yield return item.Value;
  }
}

Or simply any object:

static public class NamedInstanceManager
{
  static private readonly Dictionary<string, object> RegisteredArrays
    = new Dictionary<string, object>();

  static public void Register(string name, object instance)
  {
    if ( !RegisteredArrays.ContainsKey(name)
      && !RegisteredArrays.ContainsValue(instance) )
      RegisteredArrays.Add(name, instance);
  }

  static public void Unregister(string name)
  {
    if ( RegisteredArrays.ContainsKey(name) )
      RegisteredArrays.Remove(name);
  }

  static public void Unregister(object instance)
  {
    if ( RegisteredArrays.ContainsValue(instance) )
    {
      var item = RegisteredArrays.FirstOrDefault(kvp => kvp.Value.Equals(instance)).Key;
      RegisteredArrays.Remove(item);
    }
  }

  static public IEnumerable<object> Find(string name)
  {
    foreach ( var item in RegisteredArrays )
      if ( item.Key == name )
        yield return item.Value;
  }
}

Also we can manage registering and unregistering several differents names for the same reference and so on... by throwing an exception, returning a bool or do nothing.

Here the code only accept to add a name or a reference only if both is not already in the collection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM