C#字符串运算符重载

时间:2010-04-06 19:20:11

标签: c# operator-overloading

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;
       }
   }

}

7 个答案:

答案 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
    }