C# 字符串运算符重载

发布于 2024-08-27 20:59:26 字数 492 浏览 6 评论 0原文

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

}

G'Day Mates -

What is the right way (excluding the argument of whether it is advisable) to overload the string operators <, >, <= and >= ?

I've tried it five ways to Sunday and I get various errors - my best shot was declaring a partial class and overloading from there, but it won't work for some reason.

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

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

甩你一脸翔 2024-09-03 20:59:26

String 是一个密封类。您不能从它继承,并且如果没有 String 的原始源,您就无法编译它的部分类。即使您掌握了源代码(可以通过 Reflector 或 Visual Studio 符号下载),您仍然会遇到问题,因为它是运行时的一等公民。

你真的需要<和>作为字符串上的运算符?如果是这样...为什么不直接使用扩展方法

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

String is a sealed class. You cannot inherit from it, and without the original source for String, you cannot compile a partial class of it. Even if you got your hands on the source (it's possible via Reflector or via Visual Studio symbol download) you'd still have problems, since it's a first class citizen in the runtime.

Do you really need < and > as operators on string? If so... why not just use 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
叶落知秋 2024-09-03 20:59:26

无法将编译器的任何内置行为替换为您自己的行为。您不能覆盖用于比较、转换、算术等的现有内置运算符。这是设计使然;这样别人就可以阅读您的代码并知道 int x = M(); int y = x + 2; 进行整数算术,而不是格式化硬盘。

您能解释一下为什么要这样做吗?也许有更好的方法来做你想做的事。

There is no way to replace any built-in behaviour of the compiler with your own. You cannot override existing built-in operators for comparisons, conversions, arithmetic, and so on. That's by design; it's so that someone can read your code and know that int x = M(); int y = x + 2; does integer arithmetic, as opposed to, say, formatting your hard disk.

Can you explain why you want to do this? Perhaps there is a better way to do what you want.

℡寂寞咖啡 2024-09-03 20:59:26

简单的答案是你不能;无法修改另一个类的运算符。部分类仅适用于在所有文件中声明部分在同一程序集中定义的类。

The simple answer is that you can't; there's no way to modify the operators for another class. Partial classes are only allowed for classes that are both declared partial in all files and defined in the same assembly.

想你只要分分秒秒 2024-09-03 20:59:26

您是指 System.String 类吗?这在 C# 中是不可能的。您无法将扩展运算符添加到现有类中。不过,这是一个非常需要的功能。

Do you mean the System.String class? That's impossible in C#. You can't add extension operators to an existing class. It's a much requested feature though.

℡Ms空城旧梦 2024-09-03 20:59:26
  • 字符串的分部类,因为字符串类本身不是部分,因此无法与您的分部类一起使用。

  • 字符串是密封的,因此您可以继承它,然后重载该运算符。

简而言之,唉,你不能做你想做的事。

不知道你到底想做什么,我无法建议一个好的选择。但是,请查看扩展方法,这通常对情况有好处。暂且不论您是否应该:),您可以向字符串类添加一个名为IsGreaterThan 的方法,并根据您的意愿返回 true 或 false。这很好,因为您可以为扩展方法指定一个使其含义清晰的名称,保持现有运算符完好无损(无论如何您别无选择),并允许快速/简单的代码。

  • You can't have a partial class for string, because the string class itself is not partial and hence won't work with your partial class.

  • String is sealed, so you can inherit from it and then overload the operator.

In short, alas, you can't do what you with to do.

Not know what you're trying to do exactly, I can't suggest a good alternative. But, take a look at extension methods, which are often good for situations. Leaving aside whether you should :), you could add to the string class a method called IsGreaterThan and return true or false however you wish. This is good because you can give the extension method a name that makes it's meaning clear, keeps the existing operators in tact (which you have no choice about anyway), and allows for quick/simple code.

情泪▽动烟 2024-09-03 20:59:26

您不能直接重载 >= 和 <= 运算符,但可以通过重载 > 来获得相同的结果。和 == 分开。

你的代码对我来说似乎是正确的,除了你错过了 == 的重载这一事实。

看来我错了,但是,你总是可以退回到反思。我认为如果您进行一些挖掘和黑客攻击,您可以使其与反射一起扩展类,因为反射允许在运行时添加函数或交换函数体。

我怀疑这是否是可取和良好的做法。班级被密封是有原因的。由于 .net 框架对字符串所做的一些假设,在某些情况下执行我提到的操作可能会导致未定义的行为。 string 类内部崩溃的可能性很大。

You cannot directly overload the >= and <= operator, but you can achieve the same result by overload the > and the == separately.

Your code seems correct to me, except the fact that you miss the overloading for ==.

Seems I was wrong, however, you can always fall back to reflection. I think if you do some digging and hacking, you can make it work with reflection to extend the class since reflection allows to add functions or swap function bodies at runtime.

Whether it is advisable and good practice, I doubt it. There is a reason why the class is sealed. Doing the thing I mentioned may result in undefined behavior in some circumstances due to some assumptions the .net framework makes on strings. Chances are big that the string class will collapse internally.

谜兔 2024-09-03 20:59:26

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
    }

After 10 years you can do it (to some degree) using a wrapper class and implicit conversions.
But just because you can doesn't mean you should.

Here it is some code:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文