I am making a wrapper for a "word" in an emulator project. Its meant to put all my cast conversions all in one spot. I was just about to start implement all the overrides for math functions (+,-,/,8, shift, etc.) When it occured to me that shouldn't all the implicit's take care of that? Do I need to over ride >= and <= when I got > < and ==?
I thought I would ask this as while there are plenty of questions relating to how to create them, there aren't many on how much is enough. Here is the code below:
public struct word_t
{
ulong val;
word_t(ulong val) { this.val = val; }
public static implicit operator word_t(int a) { return new word_t((ulong)a); }
public static implicit operator word_t(long a) { return new word_t((ulong)a); }
public static implicit operator word_t(uint a) { return new word_t((ulong)a); }
public static implicit operator word_t(ulong a) { return new word_t((ulong)a); }
public static implicit operator int(word_t a) { return (int)a.val; }
public static implicit operator long(word_t a) { return (long)a.val; }
public static implicit operator uint(word_t a) { return (uint)a.val; }
public static implicit operator ulong(word_t a) { return (ulong)a.val; }
public static bool operator ==(word_t a, word_t b) { return a.val == b.val; }
public static bool operator !=(word_t a, word_t b) { return a.val != b.val; }
public static bool operator >(word_t a, word_t b) { return a.val > b.val; }
public static bool operator <(word_t a, word_t b) { return a.val < b.val; }
public override bool Equals(object obj) {
return obj.Equals(val);
}
public override int GetHashCode() {
return val.GetHashCode();
}
public override string toString() {
return val.ToString();
}
}
My gut tells me to "Trust the compiler" but my head always worries on how efficient it is.
PS I just realized I should override shifts because of the bit shifting of negative number problems, but for right now just imagine shifts just magically work like adds between uint and int.
I recommend this MSDN article: http://msdn.microsoft.com/en-us/library/8edha89s(v=VS.100).aspx
It shows the operators you can overload and any catches. You can overload <= and >= but they must be overloaded in pairs, as is true with == and != as well.
The complex match operators +=, etc are available if +, etc. is overloaded, etc.
>= and <=, however, are separate. That is, overloading > and == does not give you a >= operator implicitly.
Related
I want to implement my own CustomNumber class, and have it comparable to all other primitive number datatypes (int, long, double, float, etc.) using the relational operators.
Is there a way to do that for all of them at once, or do I really have to override the ==, !=, >, <, >= and <= operators aswell as the Equals(T other) method for each single integral datatype?
I think I know how operator overloading works in general, but it feels like there must be some kind of shortcut in order to make my CustomNumber comparable to all primitive number datatypes using relational operators, instead of having to overload each of those 6 operators for each single datatype, which might quickly add up to about 100 overload definitions.
There is no shortcut per se, you have to implement all the operators and functionality for all the types you want to support, it can't read your mind.
Check out the decimal implementation.
For your sanity you will notice not everything needs to be overridden, this is done by the implementation of implicit operators:
public static implicit operator Decimal(byte value)
{
return new Decimal(value);
}
[CLSCompliant(false)]
public static implicit operator Decimal(sbyte value)
{
return new Decimal(value);
}
public static implicit operator Decimal(short value)
{
return new Decimal(value);
}
[CLSCompliant(false)]
public static implicit operator Decimal(ushort value)
{
return new Decimal(value);
}
public static implicit operator Decimal(char value)
{
return new Decimal(value);
}
public static implicit operator Decimal(int value)
{
return new Decimal(value);
}
[CLSCompliant(false)]
public static implicit operator Decimal(uint value)
{
return new Decimal(value);
}
public static implicit operator Decimal(long value)
{
return new Decimal(value);
}
[CLSCompliant(false)]
public static implicit operator Decimal(ulong value)
{
return new Decimal(value);
}
public static explicit operator Decimal(float value)
{
return new Decimal(value);
}
public static explicit operator Decimal(double value)
{
return new Decimal(value);
}
public static explicit operator byte(Decimal value)
{
return ToByte(value);
}
[CLSCompliant(false)]
public static explicit operator sbyte(Decimal value)
{
return ToSByte(value);
}
public static explicit operator char(Decimal value)
{
UInt16 temp;
try
{
temp = ToUInt16(value);
}
catch (OverflowException e)
{
throw new OverflowException(Environment.GetResourceString("Overflow_Char"), e);
}
return (char)temp;
}
public static explicit operator short(Decimal value)
{
return ToInt16(value);
}
[CLSCompliant(false)]
public static explicit operator ushort(Decimal value)
{
return ToUInt16(value);
}
public static explicit operator int(Decimal value)
{
return ToInt32(value);
}
[CLSCompliant(false)]
public static explicit operator uint(Decimal value)
{
return ToUInt32(value);
}
public static explicit operator long(Decimal value)
{
return ToInt64(value);
}
[CLSCompliant(false)]
public static explicit operator ulong(Decimal value)
{
return ToUInt64(value);
}
public static explicit operator float(Decimal value)
{
return ToSingle(value);
}
public static explicit operator double(Decimal value)
{
return ToDouble(value);
}
public static Decimal operator +(Decimal d)
{
return d;
}
public static Decimal operator -(Decimal d)
{
return Negate(d);
}
public static Decimal operator ++(Decimal d)
{
return Add(d, One);
}
public static Decimal operator --(Decimal d)
{
return Subtract(d, One);
}
[System.Security.SecuritySafeCritical] // auto-generated
public static Decimal operator +(Decimal d1, Decimal d2)
{
FCallAddSub(ref d1, ref d2, DECIMAL_ADD);
return d1;
}
[System.Security.SecuritySafeCritical] // auto-generated
public static Decimal operator -(Decimal d1, Decimal d2)
{
FCallAddSub(ref d1, ref d2, DECIMAL_NEG);
return d1;
}
[System.Security.SecuritySafeCritical] // auto-generated
public static Decimal operator *(Decimal d1, Decimal d2)
{
FCallMultiply(ref d1, ref d2);
return d1;
}
[System.Security.SecuritySafeCritical] // auto-generated
public static Decimal operator /(Decimal d1, Decimal d2)
{
FCallDivide(ref d1, ref d2);
return d1;
}
public static Decimal operator %(Decimal d1, Decimal d2)
{
return Remainder(d1, d2);
}
[System.Security.SecuritySafeCritical] // auto-generated
public static bool operator ==(Decimal d1, Decimal d2)
{
return FCallCompare(ref d1, ref d2) == 0;
}
[System.Security.SecuritySafeCritical] // auto-generated
public static bool operator !=(Decimal d1, Decimal d2)
{
return FCallCompare(ref d1, ref d2) != 0;
}
[System.Security.SecuritySafeCritical] // auto-generated
public static bool operator <(Decimal d1, Decimal d2)
{
return FCallCompare(ref d1, ref d2) < 0;
}
[System.Security.SecuritySafeCritical] // auto-generated
public static bool operator <=(Decimal d1, Decimal d2)
{
return FCallCompare(ref d1, ref d2) <= 0;
}
[System.Security.SecuritySafeCritical] // auto-generated
public static bool operator >(Decimal d1, Decimal d2)
{
return FCallCompare(ref d1, ref d2) > 0;
}
[System.Security.SecuritySafeCritical] // auto-generated
public static bool operator >=(Decimal d1, Decimal d2)
{
return FCallCompare(ref d1, ref d2) >= 0;
}
As partial shortcut you can limit your overrides to double which cover all regular "numeric" types at cost of compiler inserted cast. Always comparing to double is dangerous for larger integer values (int and smaller types will be precise always).
class MyType
{
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public static bool operator == (MyType x, double c)
{
// write some real code here - this one does not have a value to compare to.
return c > 42;
}
// you need all several overrides for each operator to behave in expected way
// so calling the same one (a == b)
// from a != b, b != a, b == a is a way to keep them consistent
public static bool operator == (double c, MyType x)
{
return (x == c);
}
public static bool operator != (double c, MyType x)
{
return !(c == x);
}
public static bool operator != (MyType x, double c)
{
return !(x == c);
}
}
Notes
C#/ .NET do not have built in concept of "numeric" type - this is something people ask often enough (i.e. Is there a constraint that restricts my generic method to numeric types?, Generics - where T is a number?).
don't forget to implement IEquatable<T>, IComparable, IComparable<T>...
consider if it is actually useful for your "numbers" to be able to freely mix with other types - especially for comparison with imprecise float/double which already painful enough.
Updated: How could I make a method with two paramerters to take any primitive number type, like int, uint, float, double, etc, (except bool)?
I'm currently using an object, but that means the method can accept any type.
public int[] MyNumberMethod(object a, object b)
{
if (a is int || a is uint || a is short || a is ushort || a is long || a is ulong || a is byte || a is sbyte || a is float || a is double || a is decimal)
{
if (b is int || b is uint || b is short || b is ushort || b is long || b is ulong || b is byte || b is sbyte || b is float || b is double || b is decimal)
return new int[] { Convert.ToInt32(b), Convert.ToInt32(a) };
}
return new int[] { 0, 0 };
}
This might not be as good as the other answers, but another option is to create your own structure where you only allow a value of certain data types:
public struct Number
{
#region Static methods and fields
private static readonly Type[] allowedTypes = new Type[] {
typeof(int), typeof(uint), typeof(short), typeof(ushort),
typeof(long), typeof(ulong), typeof(byte), typeof(sbyte),
typeof(float), typeof(double), typeof(decimal)
};
private static void CheckIsNumber(dynamic val) {
if (Array.IndexOf(allowedTypes, val.GetType()) == -1) { throw new InvalidCastException("Input type must be a number."); }
}
#endregion
#region Constructor
public Number(dynamic Value) {
Number.CheckIsNumber(Value);
_value = Value;
}
#endregion
#region Properties
private dynamic _value;
public dynamic Value {
get { return _value; }
set {
Number.CheckIsNumber(value);
_value = value;
}
}
#endregion
#region Overridden methods
public override bool Equals(object obj) { return _value.Equals(obj); }
public override int GetHashCode() { return _value.GetHashCode(); }
public override string ToString() { return _value.ToString(); }
#endregion
#region Conversion operators - Number
public static implicit operator Number(uint val) { return new Number(val); }
public static implicit operator Number(short val) { return new Number(val); }
public static implicit operator Number(ushort val) { return new Number(val); }
public static implicit operator Number(long val) { return new Number(val); }
public static implicit operator Number(ulong val) { return new Number(val); }
public static implicit operator Number(byte val) { return new Number(val); }
public static implicit operator Number(float val) { return new Number(val); }
public static implicit operator Number(double val) { return new Number(val); }
public static implicit operator Number(decimal val) { return new Number(val); }
#endregion
#region Conversion operators - Misc. data types
public static implicit operator int(Number num) { return (int)num.Value; }
public static implicit operator uint(Number num) { return (uint)num.Value; }
public static implicit operator short(Number num) { return (short)num.Value; }
public static implicit operator ushort(Number num) { return (ushort)num.Value; }
public static implicit operator long(Number num) { return (long)num.Value; }
public static implicit operator ulong(Number num) { return (ulong)num.Value; }
public static implicit operator byte(Number num) { return (byte)num.Value; }
public static implicit operator sbyte(Number num) { return (sbyte)num.Value; }
public static implicit operator float(Number num) { return (float)num.Value; }
public static implicit operator double(Number num) { return (double)num.Value; }
public static implicit operator decimal(Number num) { return (decimal)num.Value; }
#endregion
}
Every time you change the value or create a new instance of the structure it will verify if the input value's data type matches any of the items in the allowedTypes array. If not it will throw an InvalidCastException.
I have also added conversion operators which will let you use this as a normal number, thus you can use it pretty much like you would use any other numerical data type:
Number myNum = 3.5;
myNum += 10.4;
double something = myNum - 6.0;
However keep in mind that you must add a decimal point when working with double, float, etc. or else it will assume that the number is an integer:
Number myNum = 3.5;
myNum -= 2;
MessageBox.Show(myNum.ToString()); //Shows "1" as the second line converts 'myNum' into an integer.
All that said, here's how you would use it for your method:
public int[] MyNumberMethod(Number a, Number b)
{
try {
return new int[] { Convert.ToInt32(b), Convert.ToInt32(a) };
}
catch(InvalidCastException) {
return new int[] { 0, 0 };
}
}
And thanks to the conversion operators you won't need to specify a (Number) conversion. For example:
byte myByte = 133;
//Unnecessary.
MyNumberMethod((Number)17.4, (Number)myByte);
//This works just as fine.
MyNumberMethod(17.4, myByte);
Well since you want to use all primitive types except the bool, how about that?
public int MyNumberMethod<T>(T number) where T : struct
{
if (!(number is bool) && number.GetType().IsPrimitive)
return Convert.ToInt32(number);
return 0;
}
e.g.
MyNumberMethod<short>(5);
All numeric types (except double and float) are implicitly convertible to decimal and float is implicitly convertible to double. So if you make overloads like:
Method(double, double)
Method(decimal, double)
Method(decimal,decimal)
Method(double, decimal)
Your method will be callable with any two numbers but only with any two numbers.
First you must call other function like GenericNumberMethod, that will contain the calling to MyNumberMethod. You must have for each data type an implementacion of GenericNumberMethod with the corresponding parameter
public int MyNumberMethod(object number) {
return Convert.ToInt32(number);
}
public int GenericNumberMethod(int number) {
return MyNumberMethod(number);
}
public int GenericNumberMethod(decimal number) {
return MyNumberMethod(number);
}
I have a problem with operator resolution on generic methods.
From my understanding of section 7.3.4 of the spec within the function EqualOperatorGeneric (sample code below) the correct overload of the == operator on the type A should be found, but instead it seems to get the candidate for (object, object).
Am I doing something very obvious wrong? Is there a method to get the expected behaviour and if not can I turn the given case into a compile time or runtime error?
public class A
{
public A(int num)
{
this.Value = num;
}
public int Value { get; private set; }
public override bool Equals(object obj)
{
var other = obj as A;
if (Object.ReferenceEquals(other, null))
return false;
return Object.Equals(this.Value, other.Value);
}
public override int GetHashCode()
{
return this.Value.GetHashCode();
}
public static bool operator ==(A l, A r)
{
if (Object.ReferenceEquals(l, null))
{
return !Object.ReferenceEquals(r, null);
}
return l.Equals(r);
}
public static bool operator !=(A l, A r)
{
return !(l == r);
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(EqualOperatorGeneric(new A(1), new A(1)));
}
public static bool EqualOperatorGeneric<L, R>(L l, R r)
where L : class
where R : class
{
return l == r;
}
}
Output:
False
When EqualOperatorGeneric is compiled the == operator needs to be bound statically, when the method is compiled, to a single implementation. It is not bound separately for each separate usage of the generic method.
This is what differentiates generics from, say, C++ templates. The generic method is compiled once and then applied to every usage with every set of type arguments, whereas templates are compiled separately for each set of generic arguments.
After scrounging the spec I realized you can use the dynamic keyword to defer binding of the operator from compile time to runtime. This fixes the issues I have been having:
public static bool EqualOperatorGeneric<L, R>(L l, R r)
{
dynamic dl = l, dr = r;
return dl == dr;
}
I am working on lazy object composer
class Bitset
{
private List<bool> _data;
public Bitset(List<bool> vector)
{
_data = vector;
}
public virtual bool GetElement (int i)
{
return _data[i];
}
public Bitset(){}
}
class BitsetComposer:Bitset
{
readonly private Bitset _a,_b;
private Func<bool,bool,bool> _composer;
public BitsetComposer(Bitset a,Bitset b, Func<bool,bool,bool> composer)
{
this._a=a;
this._b=b;
this._composer=composer;
}
public override bool GetElement (int i)
{
return _composer(_a.GetElement(i),_b.GetElement(i));
}
public static BitsetComposer operator & (BitsetComposer a, BitsetComposer b)
{
return new BitsetComposer(a,b,BitsetComposer.And);
}
public static bool And(bool a,bool b){return a&b;}
}
This is not fine, because, it would be desired that & can also take base class
//replaced with
//public static BitsetComposer operator & (BitsetComposer a, BitsetComposer b)
public static BitsetComposer operator & (Bitset a, Bitset b)
{
return new BitsetComposer(a,b,BitsetComposer.And);
}
But I got error:
Error CS0563: One of the parameters of a binary operator must be the containing type
If both operands are expected to be of base class type, you only need to move the operator code to the base class.
From 7.2.2 Operator overloading:
User-defined operator declarations always require at least one of the
parameters to be of the class or struct type that contains the
operator declaration. Thus, it is not possible for a user-defined operator to have the
same signature as a predefined operator.
class Bitset
{
private List<bool> _data;
public Bitset(List<bool> vector)
{
_data = vector;
}
public virtual bool GetElement (int i)
{
return _data[i];
}
public Bitset(){}
public static BitsetComposer operator &(Bitset a, Bitset b)
{
return new BitsetComposer(a, b, BitsetComposer.And);
}
}
Like the error says, you need to make sure one of your parameters is of the BitSetComposer class.
The reason you cannot do (BitSet a, BitSet b) is because then there would be no reference to your custom class. Consider this example:
var a = new BitSet();
var b = new BitSet();
var result = a&b;
In this example there is no reason to expect the BitsetComposer's operator to be used, right? So the compiler complains when you try to overload the & operator without using a at least one of the corresponding type.
So you'll need to make three total methods:
public static BitsetComposer operator & (BitsetComposer a, BitsetComposer b)
{
return new BitsetComposer(a,b,BitsetComposer.And);
}
public static BitsetComposer operator & (BitSet a, BitsetComposer b)
{
return new BitsetComposer(a,b,BitsetComposer.And);
}
public static BitsetComposer operator & (BitsetComposer a, BitSet b)
{
return new BitsetComposer(a,b,BitsetComposer.And);
}
I need to return a method in an operator function.
public int Add()
{
return 1;
}
public static int operator +()
{
return Add;
}
I will need to do this for a multiply, subtract and divide operator/function too.
Thanks
You can't declare parameterless operators. You can declare an operator to return an appropriate delegate - e.g. Func<int> - but it would be a pretty odd thing to do, IMO.
If you can tell us more about what you're trying to achieve, we can probably help you to work out a cleaner design.
Here's a pretty strange example overloading the unary + operator:
using System;
class Weird
{
private readonly int amount;
public Weird(int amount)
{
this.amount = amount;
}
private int Add(int original)
{
return original + amount;
}
// Very strange. Please don't do this.
public static Func<int, int> operator +(Weird weird)
{
return weird.Add;
}
}
class Test
{
static void Main(string[] args)
{
Weird weird = new Weird(2);
Func<int, int> func = +weird;
Console.WriteLine(func(3));
}
}
EDIT: If you're just trying to implement a Rational type, you're more likely to want:
public struct Rational
{
// Other members
public Rational Add(Rational other)
{
...
}
public static Rational operator +(Rational left, Rational right)
{
return left.Add(right);
}
}
This is what you SEEM to be trying to do, but your example makes it difficult to tell. So, from your comments in other answers it looks like you want to add, subtract, multiply, divide Rational numbers, which means the result should be a Rational as well (not an int).
Thus, you could define each of your methods, then implement operators to call those. The operators are always static, thus you'd need to check for null and handle as appropriate (in this case, I'll just throw ArgumentNullException):
public class Rational
{
public Rational Add(Rational other)
{
if (other == null) throw new ArgumentNullException("other");
return // <-- return actual addition result here
}
public static Rational operator +(Rational left, Rational right)
{
if (left == null) throw new ArgumentNullException("left");
return left.Add(right);
}
public Rational Subtract(Rational other)
{
if (other == null) throw new ArgumentNullException("other");
return // <-- return actual subtraction result here
}
public static Rational operator -(Rational left, Rational right)
{
if (left == null) throw new ArgumentNullException("left");
return left.Subtract(right);
}
public Rational Multiply(Rational other)
{
if (other == null) throw new ArgumentNullException("other");
return // <-- return actual multiplication result here
}
public static Rational operator *(Rational left, Rational right)
{
if (left == null) throw new ArgumentNullException("left");
return left.Multiply(right);
}
public Rational Divide(Rational other)
{
if (other == null) throw new ArgumentNullException("other");
return // <-- return actual division result here
}
public static Rational operator /(Rational left, Rational right)
{
if (left == null) throw new ArgumentNullException("left");
return left.Divide(right);
}
}
Simple. Just call the Add method:
return Add();
C Sharp - Lesson 18: Overloading Operators
I don't think you can overload the + operator for int's! You would have to create your own wrapper class or struct instead:
public struct MyInt
{
private int _value;
public MyInt(int value)
{
_value = value;
}
public int Value
{
get { return _value; }
}
public static MyInt operator +(MyInt a, MyInt b)
{
return new MyInt(a._value + b._value);
}
public static implicit operator MyInt(int intValue)
{
return new MyInt(intValue);
}
public static explicit operator int(MyInt x)
{
return x.Value;
}
}
Then you are free to do with '+' what ever you want to do with it.
The implicit operator automatically converts int's to MyInt. So you could assign like this: MyInt x = 7;
The explicit operator converts MyInt's to int's like: int i = (int)x; where x is a MyInt.