白用了C#这么多年 ! 原来静态函数还有这说法 ?
起因
为了方便比较版本号,所以想到用 struct 封装一个结构体并重载它的操作符.
因为不常使用操作符重载,以为它的成员访问级别应该和普通的静态函数没有区别
直到使用时无意间发现
它竟然能访问到对应成员的私有成员 !!!
然后继续探索
发现只要静态函数的入参中有和静态函数所属类型相同的实例,该静态函数可以直接访问对应类型的入参实例的私有成员!!!
例如:
从而可以做到在重载类型操作时不必要公开一些成员访问, 达到类似 C++ 友元函数 的成员访问的效果(但是不能像C++一样在其他类中定义,只能在该类中定义) 非常便捷
例如:
也可以访问私有函数
完整代码
using System.Collections.Immutable;
using System.Security.Cryptography;
VersionNumberString v = "3.1.5";
partial class NewClass
{
private string _value;
public static void VisitPrivateMember(NewClass instance)
{
instance._value.Dump();
}
}
partial class NewClass
{
public static void PartialVisitPrivateMember(NewClass instance)
{
VisitPrivateMember(instance);
}
}
struct VersionNumberString
{
private string _value;
private char _splitCharacter;
private Lazy<ImmutableArray<int>> _parts;
private const char DEFAULT_SPLIT_CHARACTER_A = '.';
private const char DEFAULT_SPLIT_CHARACTER_B = ',';
private const char DEFAULT_SPLIT_CHARACTER_C = '&';
public VersionNumberString(string value, char splitCharacter)
{
_value = value;
_splitCharacter = splitCharacter;
_parts = new(InitParts);
}
public static implicit operator string(VersionNumberString v)
{
return v._value;
}
public static implicit operator VersionNumberString(string version)
{
var splitCharacter = VersionNumberString.DetectSplitCharacter(version);
return new VersionNumberString (version,splitCharacter);
}
private static char DetectSplitCharacter(string source)
{
var span = source.AsSpan();
int index = span.IndexOfAny(
DEFAULT_SPLIT_CHARACTER_A,
DEFAULT_SPLIT_CHARACTER_B,
DEFAULT_SPLIT_CHARACTER_C
);
// 有下标截取一个字符,没有下班直接移动到最后
var range = index != -1
? span[index..(index+1)]
: span[span.Length..];
var e = range.GetEnumerator();
if(!e.MoveNext())
{
return ' ';
}
return e.Current;
}
ImmutableArray<int> InitParts()
{
if(_splitCharacter ==' ')
{
return int.TryParse(_value,out int parsedVerion)
? ImmutableArray.Create<int>(parsedVerion)
: ImmutableArray.Create<int>();
}
var span = _value.AsSpan();
int startIndex = default;
List<int> result = new(span.Length-1);
for (int i = 0; i < span.Length; i++)
{
if (span[i] == _splitCharacter)
{
var n = int.Parse(span[startIndex..i]);
result.Add(n);
startIndex = i + 1;
}
else if (i == span.LastIndexOf(_splitCharacter) + 1)
{
var lastChar = span.Slice(i, span.Length - startIndex);
result.Add(int.Parse(lastChar));
}
}
return result.ToImmutableArray();
}
}