自定义C# 8.0 Range功能

需求

想让string支持索引为负数。
采用C#中的扩展方法进行实现。

public static class ObjectExtension
{
  public static string Span(this string val, int index)
  {
    if (null == val)
    {
      return val;
    }
    int len = val.Length;
    // when len > 0 index must be less than val's length.
    if ((len > 0 && index >= len) || Math.Abs(index) > len)
    {
      throw new IndexOutOfRangeException();
    }
    string result = index >= 0 ? val[index].ToString() : val[len + index].ToString();
    return result;
  }
}

  上述代码只是在字符串中获取按照索引读取某个字符,试想一下,是否可以截取一串字符,同样可是支持负数的呢?
  在C# 8.0,引入了Range对象,语法 Raange range=1..4;这样方式获取,从索引为 1到索引为 4但是 4不能包含,也就是读取3个字符。如果想要用负数表示: Range range=1..^4;用 ^表示负数,这个 range表示从索引 1开始到倒数第四个字符结束。
例如:

    string str = "abcedfghijklmnopqrstuvwsyz";
    Range range = 1..^4;
    string result = str[range];
    Console.WriteLine(result);
    // result : bcedfghijklmnopqrstuv

  满足上面的语法,需要将 IDE升级 Visual Studio 2019,很多公司或者很多项目组还在使用旧的 Visual Studio IDE,更有甚者,可能还在使用 Visual Studio 2005,想使用高级语法糖,只能望而却步。如果也想使用类似这样的高级语法呢?答案是肯定可行的,按照上面的扩展,写一个重载方法。

// define Range object
public struct Range
{
	private int startIndex;
	private int endIndex;
	private bool isNotNull;
	
	public Range(int startIndex, int endIndex, bool isValidate = true)
	{
		if(isValidate && startIndex > endIndex)
		{
			throw new IndexOutOfRangeException("startIndex must be equal or less than endIndex.");
		}
		this.startIndex = startIndex;
		this.endIndex = endIndex;
		this.isNotNull = true;
	}
	
	public bool IsNull
	{
		get
		{
			return !this.isNotNull;
		}
	}
	
	internal void CheckNull()
	{
		if(this.IsNull)
		{
			throw new Exception("this object is null");
		}
	}
	
	public int StartIndex
	{
		get
		{
			CheckNull();
			return this.startIndex;
		}
	}
	
	public int EndIndex
	{
		get
		{
			CheckNull();
			return this.endIndex;
		}
	}
	
	public int Count
	{
		get
		{
			if(IsNull)
			{
				return 0;
			}
			return this.endIndex - this.startIndex;
		}
	}
	
	public static implicit operator Range(string input)
	{
		if(string.IsNullOrEmpty(input))
		{
			return default(Range);
		}
		Regex re = new Regex(@"^(\^?)\d+\.\.(\^?)\d+$");
		Regex re3 = new Regex(@"^\.\.(\^?)\d+$");
		Regex re2 = new Regex(@"^(\^?)\d+\.\.$");
		Match match = null;
		int matchFlag = 0;
		if (re.IsMatch(input))
		{
			matchFlag = 1;
			match = re.Match(input);
		}
		else if (re2.IsMatch(input))
		{
			matchFlag = 2;
			match = re2.Match(input);
		}
		else if (re3.IsMatch(input))
		{
			matchFlag = 3;
			match = re3.Match(input);
		}
		// match fails
		if (0 == matchFlag)
		{
			return default(Range);
		}
		string[] strs = match.Value.Split("..");
		int startIndex, endIndex;
		int.TryParse(strs[0].Replace("^", "-"), out startIndex);
		int.TryParse(strs[1].Replace("^", "-"), out endIndex);
		if(2 == matchFlag)
		{
			endIndex = int.MaxValue;
		}else if(3 == matchFlag)
		{
			startIndex = 0;
		}
		
		return new Range(startIndex, endIndex, false);
	}
}

添加对string的扩展方法

public static class ObjectExtension
{
    public static string Span(this string val, string input)
    {
        if(string.IsNullOrEmpty(val) || string.IsNullOrEmpty(input))
        {
            return val;
        }
        // implicit convert to Range.
        Range range = input;
        int len = val.Length;
        int startIndex = range.StartIndex < 0 ? len + range.StartIndex : range.StartIndex;
	int endIndex = range.EndIndex < 0 ? len + range.EndIndex : range.EndIndex;
	if(range.EndIndex == int.MaxValue)
	{
		endIndex = len;
	}
	range = new Range(startIndex, endIndex);
        return val.Span(range);
    }

    public static string Span(this string val, Range range)
    {
        if(string.IsNullOrEmpty(val) || range.IsNull)
        {
            return val;
        }
        return val.Substring(range.StartIndex, range.Count);
    }
}

测试结果


用C#做一个String的扩展

posted @ 2020-07-02 22:10  lian-luo  阅读(653)  评论(0)    收藏  举报