G'Day Mates -
重载字符串运算符<,>,< =和> =?
的正确方法(不包括是否可取的论据)是什么?我已经尝试了五种方式来到星期天,我得到了各种各样的错误 - 我最好的镜头是从那里宣布一个部分类和超载,但是由于某种原因它不会起作用。
namespace System
{
public partial class String
{
public static Boolean operator <(String a, String b)
{
return a.CompareTo(b) < 0;
}
public static Boolean operator >(String a, String b)
{
return a.CompareTo(b) > 0;
}
}
}
答案 0 :(得分:17)
String是一个密封类。你不能继承它,如果没有String的原始源,你就无法编译它的部分类。即使您已经掌握了源(可以通过Reflector或通过Visual Studio符号下载),您仍然会遇到问题,因为它是运行时的一等公民。
你真的需要&lt;和&gt;作为字符串的运算符?如果是这样......为什么不使用extension methods?
public static bool IsLessThan(this string a, string b)
{
return a.CompareTo(b) < 0;
}
public static bool IsGreaterThan(this string a, string b)
{
return a.CompareTo(b) > 0;
}
// elsewhere...
foo.IsLessThan(bar); // equivalent to foo < bar
答案 1 :(得分:16)
无法用您自己的替换编译器的任何内置行为。您无法覆盖现有的内置运算符以进行比较,转换,算术等。这是设计的;这是因为有人可以读取你的代码并知道int x = M(); int y = x + 2;
进行整数运算,而不是格式化你的硬盘。
你能解释一下你为什么要这样做吗?也许有更好的方法来做你想做的事。
答案 2 :(得分:10)
简单的答案是你做不到;没有办法修改另一个类的运算符。部分类仅允许在所有文件中声明partial
和在同一程序集中定义的类。
答案 3 :(得分:5)
你的意思是System.String
班吗?这在C#中是不可能的。您无法将扩展运算符添加到现有类。这是一个非常需要的功能。
答案 4 :(得分:3)
您不能拥有字符串的部分类,因为字符串类本身不是部分,因此不适用于您的部分类。
字符串是密封的,因此您可以从中继承,然后重载运算符。
简而言之,唉,你不能做你要做的事。
不知道你究竟要做什么,我不能建议一个好的选择。但是,请查看 extension methods ,这些情况通常很有用。暂且不管你应该 :),你可以在字符串类中添加一个名为 IsGreaterThan 的方法,然后根据需要返回true或false。这很好,因为你可以给扩展方法一个名称,使其意义清晰,保持现有的操作符(无论如何都没有选择),并允许快速/简单的代码。
答案 5 :(得分:1)
你不能直接重载&gt; =和&lt; =运算符,但你可以通过重载&gt;来实现相同的结果。和==分开。
你的代码对我来说似乎是正确的,除了你错过了==的重载。
似乎我错了,但是,你总能回到反思。我认为如果你做一些挖掘和黑客攻击,你可以使用反射来扩展类,因为反射允许在运行时添加函数或交换函数体。
无论是可取的还是良好的做法,我都怀疑。课程有密封的原因。由于.net框架对字符串做出的一些假设,执行我提到的事情可能会在某些情况下导致未定义的行为。字符串类在内部崩溃的可能性很大。
答案 6 :(得分:-1)
10年后,您可以使用包装器类和隐式转换来做到(在某种程度上)。
但是,仅仅因为您可以做,并不意味着您应该做。
这是一些代码:
// implements all interfaces that string does through the field content
public sealed class StringWrapper : IEnumerable<char>, ICloneable, IComparable, IComparable<string>, IConvertible, IEquatable<string>
{
private readonly string content;
private StringWrapper(string content)
{
this.content = content;
}
// implicit conversions
public static implicit operator string(StringWrapper d) => d.content;
public static implicit operator StringWrapper(string b) => new StringWrapper(b);
public static bool operator <(StringWrapper lhs, StringWrapper rhs)
{
return lhs.content.CompareTo(rhs.content) < 0;
}
public static bool operator >(StringWrapper lhs, StringWrapper rhs)
{
return lhs.content.CompareTo(rhs.content) > 0;
}
// string supports it, why shouldnt we?
public static StringWrapper operator +(StringWrapper lhs, StringWrapper rhs)
{
var sb = new StringBuilder();
sb.Append(lhs.content);
sb.Append(rhs.content);
return sb.ToString();
}
// at request of @Alexey Khoroshikh
public static StringWrapper operator *(StringWrapper lhs, int rhs)
{
var sb = new StringBuilder();
for (int i = 0; i < rhs; i++)
{
sb.Append(lhs.content);
}
return sb.ToString();
}
// other nice thing to have
public static string[] operator /(StringWrapper lhs, char rhs)
{
return lhs.content.Split(rhs);
}
public override bool Equals(object obj)
{
return (obj is StringWrapper wrapper && content == wrapper.content)
|| (obj is string str && content == str);
}
#region auto-generated code through visual studio
public override int GetHashCode()
{
return -1896430574 + EqualityComparer<string>.Default.GetHashCode(content);
}
public override string ToString()
{
return this.content;
}
public object Clone()
{
return content.Clone();
}
public int CompareTo(string other)
{
return content.CompareTo(other);
}
public bool Equals(string other)
{
return content.Equals(other);
}
public IEnumerator<char> GetEnumerator()
{
return ((IEnumerable<char>)content).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((System.Collections.IEnumerable)content).GetEnumerator();
}
public int CompareTo(object obj)
{
return content.CompareTo(obj);
}
public TypeCode GetTypeCode()
{
return content.GetTypeCode();
}
public bool ToBoolean(IFormatProvider provider)
{
return ((IConvertible)content).ToBoolean(provider);
}
public byte ToByte(IFormatProvider provider)
{
return ((IConvertible)content).ToByte(provider);
}
public char ToChar(IFormatProvider provider)
{
return ((IConvertible)content).ToChar(provider);
}
public DateTime ToDateTime(IFormatProvider provider)
{
return ((IConvertible)content).ToDateTime(provider);
}
public decimal ToDecimal(IFormatProvider provider)
{
return ((IConvertible)content).ToDecimal(provider);
}
public double ToDouble(IFormatProvider provider)
{
return ((IConvertible)content).ToDouble(provider);
}
public short ToInt16(IFormatProvider provider)
{
return ((IConvertible)content).ToInt16(provider);
}
public int ToInt32(IFormatProvider provider)
{
return ((IConvertible)content).ToInt32(provider);
}
public long ToInt64(IFormatProvider provider)
{
return ((IConvertible)content).ToInt64(provider);
}
public sbyte ToSByte(IFormatProvider provider)
{
return ((IConvertible)content).ToSByte(provider);
}
public float ToSingle(IFormatProvider provider)
{
return ((IConvertible)content).ToSingle(provider);
}
public string ToString(IFormatProvider provider)
{
return content.ToString(provider);
}
public object ToType(Type conversionType, IFormatProvider provider)
{
return ((IConvertible)content).ToType(conversionType, provider);
}
public ushort ToUInt16(IFormatProvider provider)
{
return ((IConvertible)content).ToUInt16(provider);
}
public uint ToUInt32(IFormatProvider provider)
{
return ((IConvertible)content).ToUInt32(provider);
}
public ulong ToUInt64(IFormatProvider provider)
{
return ((IConvertible)content).ToUInt64(provider);
}
#endregion auto-generated code through visual studio
}