简体   繁体   中英

How to facilitate the type refactoring of a C# variable?

For example, I have a code fragment like this:

IEnumerable<int> _en;
object _lock = new Object();

void Enumerate()
{
    IEnumerable<int> en = null;

    lock (_lock)
    {
        en = _en;
        _en = new List<int>();
        // ...
    }

    foreach (var i in en)
    {
        // ...
    }
}

I want to change the item type from int to double , so I have at least 3 places to attend and change it. To facilitate this, does something like the following make sense? Is there anything else I can do?

IEnumerable<int> _en;
object _lock = new Object();

void Enumerate()
{
    var en = GetDefault(_en);

    lock (_lock)
    {
        en = _en;
        _en = CreateEmptyList(_en);
        // ...
    }

    foreach (var i in en)
    {
        // ...
    }
}

static T GetDefault<T>(T arg)
{
    return default(T);
}

static List<T> CreateEmptyList<T>(IEnumerable<T> arg)
{
    return new List<T>();
}

The Problem:

As I have decided to understand it, you want to minimize effort of menial refactoring tasks amongst constantly changing requirements in your work environment by creating some way of lowering the number of overall places you'd need to change code during this refactoring.

One Possible Solution:

You can obfuscate to a point.

Important Note: Places where your code is called may have to be refactored if you want to change from, double to int. Basically covariance and contravariance comes into play.

double example = 2; // works
int example2 = 2.5; // needs to manually be refactored
  • So with that in mind, you can create your class as a generic base class that accepts a value type and you'd then create a pass-through subclass that defines that value type (int, double, etc.).

  • You'd want to provide methods that don't require the explicit creation of, say List all over the place because then when refactoring, all that has to be changed.

Here's an example of a method that can do something like this:

// We use params T[] here to reduce the need for any calling code to declare,
// for example, a List<int>, which would later need to potentially be changed in
// many places.
public void SetEnumerable(params T[] value)
{
    _en = value;
}    
  • And you would call it with just the numeric values: (As per my first note, if you change the underlying generic type from int to double , this will continue to work; however if you change from double to int , then the calling code won't compile until it is refactored.

Example:

// Here we use the SetEnumerable method without declaring a List<int>.
// Therefore, if you later change underlying type to double, the code 
// below can remain unchanged.
var myEnumerable = new MyEnumerable();
myEnumerable.SetEnumerable(1, 2, 3); 

The class structure could look something like this:

Note I'm not suggesting this is a great practice, and am merely attempting to provide a possible solution to your distinct problem in this case. The merits of this solution in terms of performance and/or whether it's a good idea are outside the scope of this answer :)

public class MyEnumerable : EnumerateBase<int> { }

public class EnumerateBase<T> where T :  struct 
{
    private IEnumerable<T> _en;
    object _lock = new Object();

    public void SetEnumerable(params T[] value)
    {
        _en = value;
    }

    public void Enumerate()
    {
        IEnumerable<T> en = null;

        lock (_lock)
        {
            en = _en;
            _en = new List<T>();
            // ...
        }

        foreach (var i in en) { /* ... */ }
    }
}

In this example, the datatype int is only declared in one place, making refactoring relatively simple.

Hopefully, this gives you some food for thought and insight into how to approach your stated problem.

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