Code:
void Main()
{
C.F();
}
public class C
{
public static void F()
{
var a = new A { i = 1, d = 2.5m };
var b = new B(a);
I(b);
D(b);
}
static void I(int i) { Console.WriteLine("int is: " + i); }
static void D(decimal d) { Console.WriteLine("decimal is: " + d); }
}
public class A
{
public int i;
public decimal d;
}
public class B
{
A _a;
public B(A a) { _a = a; }
public static implicit operator int(B b) { return b._a.i; }
public static implicit operator decimal(B b) { return b._a.d; }
}
OUTPUT:
int is: 1
decimal is: 2.5
Comment out:
//public static implicit operator decimal(B b) { return b._a.d; }
OUTPUT:
int is: 1
decimal is: 1
What is going on when the second version runs and outputs 1 for both cases?
My guess is that the compiler sees that there is an implicit conversion from B to int, and an implicit (built-in) conversion from int to decimal, so that it can use both in sequence. In other words, the call becomes D((decimal)(int)b).
Note that nothing is being truncated; rather, an int is being promoted to a decimal. If instead you comment out the int conversion, I expect that I(b) will fail, since even though there is an implicit cast from B to decimal, there is no implicit cast from decimal to int.
when you comment that line out it takes the int operator because there is an implicit conversion of int to decimal...
Related
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);
}
public struct DecimalOrNaN
{
public decimal Value;
public bool isNaN;
public DecimalOrNaN (double D)
{
if (Double.IsNaN(D))
{
Value = default(decimal);
isNaN = true;
}
else
{
Value = (decimal)D;
isNaN = false;
}
}
public DecimalOrNaN(decimal D)
{
Value = D;
isNaN = false;
}
public implicit operator DecimalOrNaN(double D)
{
return new DecimalOrNaN(D);
}
public implicit operator DecimalOrNaN(decimal D)
{
return new DecimalOrNaN(D);
}
public DecimalOrNaN operator *(int I, DecimalOrNaN D)
{
return new DecimalOrNaN(D.Value * I);
}
}
I have this struct (let's just call it DON) here which stores decimals, but has an option to have "Not a Number" in it, which regular decimal lacks. I can add the needed implicit conversions myself, but i also need it to be able to add, subtract and multiply with other DONs as well as with ints, doubles and decimals. Do I have to create each operator with each variation of parameters (int + DON, DON + int, int * DON,DON * int and so on) myself or is there a better way of doing it?
My suggestion would be to use the nullable type: decimal?. This will allow you to assign NULL to the variable to indicate it's not a number.
Documentation for this feature of the language is available here: http://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx
tl;dr: What's wrong with my Cur (currency) structure?
tl;dr 2: Read the rest of the question please, before giving an example with float or double. :-)
I'm aware that this question has come up numerous times before all around the internet, but I have not yet seen a convincing answer, so I thought I'd ask again.
I fail to understand why using a non-decimal data type is bad for handling money. (That refers to data types that store binary digits instead of decimal digits.)
True, it's not wise to compare two doubles with a == b. But you can easily say a - b <= EPSILON or something like that.
What is wrong with this approach?
For instance, I just made a struct in C# that I believe handles money correctly, without using any decimal-based data formats:
struct Cur
{
private const double EPS = 0.00005;
private double val;
Cur(double val) { this.val = Math.Round(val, 4); }
static Cur operator +(Cur a, Cur b) { return new Cur(a.val + b.val); }
static Cur operator -(Cur a, Cur b) { return new Cur(a.val - b.val); }
static Cur operator *(Cur a, double factor) { return new Cur(a.val * factor); }
static Cur operator *(double factor, Cur a) { return new Cur(a.val * factor); }
static Cur operator /(Cur a, double factor) { return new Cur(a.val / factor); }
static explicit operator double(Cur c) { return Math.Round(c.val, 4); }
static implicit operator Cur(double d) { return new Cur(d); }
static bool operator <(Cur a, Cur b) { return (a.val - b.val) < -EPS; }
static bool operator >(Cur a, Cur b) { return (a.val - b.val) > +EPS; }
static bool operator <=(Cur a, Cur b) { return (a.val - b.val) <= +EPS; }
static bool operator >=(Cur a, Cur b) { return (a.val - b.val) >= -EPS; }
static bool operator !=(Cur a, Cur b) { return Math.Abs(a.val - b.val) < EPS; }
static bool operator ==(Cur a, Cur b) { return Math.Abs(a.val - b.val) > EPS; }
bool Equals(Cur other) { return this == other; }
override int GetHashCode() { return ((double)this).GetHashCode(); }
override bool Equals(object o) { return o is Cur && this.Equals((Cur)o); }
override string ToString() { return this.val.ToString("C4"); }
}
(Sorry for changing the name Currency to Cur, for the poor variable names, for omitting the public, and for the bad layout; I tried to fit it all onto the screen so that you could read it without scrolling.) :)
You can use it like:
Currency a = 2.50;
Console.WriteLine(a * 2);
Of course, C# has the decimal data type, but that's beside the point here -- the question is about why the above is dangerous, not why we shouldn't use decimal.
So would someone mind providing me with a real-world counterexample of a dangerous statement that would fail for this in C#? I can't think of any.
Thanks!
Note: I am not debating whether decimal is a good choice. I'm asking why a binary-based system is said to be inappropriate.
Floats aren't stable for accumulating and decrementing funds. Here's your actual example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BadFloat
{
class Program
{
static void Main(string[] args)
{
Currency yourMoneyAccumulator = 0.0d;
int count = 200000;
double increment = 20000.01d; //1 cent
for (int i = 0; i < count; i++)
yourMoneyAccumulator += increment;
Console.WriteLine(yourMoneyAccumulator + " accumulated vs. " + increment * count + " expected");
}
}
struct Currency
{
private const double EPSILON = 0.00005;
public Currency(double value) { this.value = value; }
private double value;
public static Currency operator +(Currency a, Currency b) { return new Currency(a.value + b.value); }
public static Currency operator -(Currency a, Currency b) { return new Currency(a.value - b.value); }
public static Currency operator *(Currency a, double factor) { return new Currency(a.value * factor); }
public static Currency operator *(double factor, Currency a) { return new Currency(a.value * factor); }
public static Currency operator /(Currency a, double factor) { return new Currency(a.value / factor); }
public static Currency operator /(double factor, Currency a) { return new Currency(a.value / factor); }
public static explicit operator double(Currency c) { return System.Math.Round(c.value, 4); }
public static implicit operator Currency(double d) { return new Currency(d); }
public static bool operator <(Currency a, Currency b) { return (a.value - b.value) < -EPSILON; }
public static bool operator >(Currency a, Currency b) { return (a.value - b.value) > +EPSILON; }
public static bool operator <=(Currency a, Currency b) { return (a.value - b.value) <= +EPSILON; }
public static bool operator >=(Currency a, Currency b) { return (a.value - b.value) >= -EPSILON; }
public static bool operator !=(Currency a, Currency b) { return Math.Abs(a.value - b.value) <= EPSILON; }
public static bool operator ==(Currency a, Currency b) { return Math.Abs(a.value - b.value) > EPSILON; }
public bool Equals(Currency other) { return this == other; }
public override int GetHashCode() { return ((double)this).GetHashCode(); }
public override bool Equals(object other) { return other is Currency && this.Equals((Currency)other); }
public override string ToString() { return this.value.ToString("C4"); }
}
}
On my box this gives $4,000,002,000.0203 accumulated vs. 4000002000 expected in C#. It's a bad deal if this gets lost over many transactions in a bank - it doesn't have to be large ones, just many. Does that help?
Usually monetary calculations require exact results, not just accurate results. float and double types cannot accurately represent the whole range of base 10 real numbers. For instance, 0.1 cannot be represented by a floating-point variable. What will be stored is the nearest representable value, which may be a number such as 0.0999999999999999996. Try it out for yourself by unit testing your struct - for example, attempt 2.00 - 1.10.
I'm not sure why you're shrugging off J Trana's answer as irrelevant. Why don't you try it yourself? The same example works with your struct too. You just need to add a couple extra iterations because you're using a double instead of a float, which gives you a bit more precision. Just delays the problem, doesn't get rid of it.
Proof:
class Program
{
static void Main(string[] args)
{
Currency currencyAccumulator = new Currency(0.00);
double doubleAccumulator = 0.00f;
float floatAccumulator = 0.01f;
Currency currencyIncrement = new Currency(0.01);
double doubleIncrement = 0.01;
float floatIncrement = 0.01f;
for(int i=0; i<100000000; ++i)
{
currencyAccumulator += currencyIncrement;
doubleAccumulator += doubleIncrement;
floatAccumulator += floatIncrement;
}
Console.WriteLine("Currency: {0}", currencyAccumulator);
Console.WriteLine("Double: {0}", doubleAccumulator);
Console.WriteLine("Float: {0}", floatAccumulator);
Console.ReadLine();
}
}
struct Currency
{
private const double EPSILON = 0.00005;
public Currency(double value) { this.value = value; }
private double value;
public static Currency operator +(Currency a, Currency b) { return new Currency(a.value + b.value); }
public static Currency operator -(Currency a, Currency b) { return new Currency(a.value - b.value); }
public static Currency operator *(Currency a, double factor) { return new Currency(a.value * factor); }
public static Currency operator *(double factor, Currency a) { return new Currency(a.value * factor); }
public static Currency operator /(Currency a, double factor) { return new Currency(a.value / factor); }
public static Currency operator /(double factor, Currency a) { return new Currency(a.value / factor); }
public static explicit operator double(Currency c) { return System.Math.Round(c.value, 4); }
public static implicit operator Currency(double d) { return new Currency(d); }
public static bool operator <(Currency a, Currency b) { return (a.value - b.value) < -EPSILON; }
public static bool operator >(Currency a, Currency b) { return (a.value - b.value) > +EPSILON; }
public static bool operator <=(Currency a, Currency b) { return (a.value - b.value) <= +EPSILON; }
public static bool operator >=(Currency a, Currency b) { return (a.value - b.value) >= -EPSILON; }
public static bool operator !=(Currency a, Currency b) { return Math.Abs(a.value - b.value) <= EPSILON; }
public static bool operator ==(Currency a, Currency b) { return Math.Abs(a.value - b.value) > EPSILON; }
public bool Equals(Currency other) { return this == other; }
public override int GetHashCode() { return ((double)this).GetHashCode(); }
public override bool Equals(object other) { return other is Currency && this.Equals((Currency)other); }
public override string ToString() { return this.value.ToString("C4"); }
}
Result:
Currency: $1,000,000.0008
Double: 1000000.00077928
Float: 262144
We're only up to .08 cents, but eventually that'll add up.
Your edit:
static void Main(string[] args)
{
Currency c = 1.00;
c /= 100000;
c *= 100000;
Console.WriteLine(c);
Console.ReadLine();
}
}
struct Currency
{
private const double EPS = 0.00005;
private double val;
public Currency(double val) { this.val = Math.Round(val, 4); }
public static Currency operator +(Currency a, Currency b) { return new Currency(a.val + b.val); }
public static Currency operator -(Currency a, Currency b) { return new Currency(a.val - b.val); }
public static Currency operator *(Currency a, double factor) { return new Currency(a.val * factor); }
public static Currency operator *(double factor, Currency a) { return new Currency(a.val * factor); }
public static Currency operator /(Currency a, double factor) { return new Currency(a.val / factor); }
public static Currency operator /(double factor, Currency a) { return new Currency(a.val / factor); }
public static explicit operator double(Currency c) { return Math.Round(c.val, 4); }
public static implicit operator Currency(double d) { return new Currency(d); }
public static bool operator <(Currency a, Currency b) { return (a.val - b.val) < -EPS; }
public static bool operator >(Currency a, Currency b) { return (a.val - b.val) > +EPS; }
public static bool operator <=(Currency a, Currency b) { return (a.val - b.val) <= +EPS; }
public static bool operator >=(Currency a, Currency b) { return (a.val - b.val) >= -EPS; }
public static bool operator !=(Currency a, Currency b) { return Math.Abs(a.val - b.val) < EPS; }
public static bool operator ==(Currency a, Currency b) { return Math.Abs(a.val - b.val) > EPS; }
public bool Equals(Currency other) { return this == other; }
public override int GetHashCode() { return ((double)this).GetHashCode(); }
public override bool Equals(object o) { return o is Currency && this.Equals((Currency)o); }
public override string ToString() { return this.val.ToString("C4"); }
}
Prints $0.
Mehrdad, I don't think I could convince you if I brought in the entire SEC. Now, your entire class basically implements BigInteger arithmetic with an implied shift of 2 decimal places. (It should be at least 4 for accounting purposes, but we can change 2 to 4 easily enough.)
What advantage do we have backing this class with double instead of BigDecimal (or longlong if something like that is available)? For the advantage of a primitive type I pay with expensive rounding operations. And I also pay with inaccuracies. [Example from here 1]
import java.text.*;
public class CantAdd {
public static void main(String[] args) {
float a = 8250325.12f;
float b = 4321456.31f;
float c = a + b;
System.out.println(NumberFormat.getCurrencyInstance().format(c));
}
}
OK, here we backed with a float instead of a double, but shouldn't that be a BIG warning flag that the whole concept is wrong and that we may get in trouble if we have to make millions of calculations?
Every professional who works in finance believes that floating-point representation of money are a bad idea. (See, among dozens of hits, http://discuss.joelonsoftware.com/default.asp?design.4.346343.29.) Which is more likely: they are all stupid, or floating-point money is indeed a bad idea?
Cur c = 0.00015;
System.Console.WriteLine(c);
// rounds to 0.0001 instead of the expected 0.0002
The problem is that 0.00015 in binary is really 0.00014999999999999998685946966947568625982967205345630645751953125, which rounds down, but the exact decimal value rounds up.
public class Racional<T>
{
private T nominator;
private T denominator;
public T Nominator
{
get { return nominator; }
set { nominator = value; }
}
public T Denominator
{
get { return denominator; }
set { denominator = value; }
}
public Racional(T nominator, T denominator)
{
this.nominator = nominator;
this.denominator = denominator;
}
public static Racional<int> operator *(Racional<int> a, Racional<int> b)
{
return ((int)(a.nominator + b.nominator, a.denominator + b.denominator));
}
public override string ToString()
{
return "(" + this.nominator + " " + this.denominator + ")";
}
}
I'm interested in this part :
public static Racional<int> operator *(Racional<int> a, Racional<int> b)
{
return ((int)(a.nominator + b.nominator, a.denominator + b.denominator));
}
What's wrong:
One of the parameters of a binary operator must be the containing type
How I can normaly code this part for mathematic operations?
The reason your code doesn't compile is explained by the compiler error. The containing type is a generic type definition, and a generic type constructed from such a type is not considered to be the same type.
I have a few questions:
Why must the Rational type be generic? A rational number is defined as a number that can be expressed as the quotient / fraction of two integers (where the denominator is not 0). Why not make the type non-generic and simply use int throughout? Or do you intend that the type be used for other integral types such as long and BigInteger? In that case, consider using something like Aliostad's suggestion if you want some code-sharing mechanism.
Why do you want the product of two rational numbers to be the equal to the sum of their numerators over the sum of their denominators? That doesn't make sense to me.
In any case, you appear to want to be able to 'generically' add two instances of an 'addable' type. Unfortunately, there currently isn't any way to express a 'has a suitable addition operator' constraint in C#.
Method #1: One workaround for this in C# 4 is to use the dynamic type to give you the desired "virtual operator" semantics.
public static Racional<T> operator *(Racional<T> a, Racional<T> b)
{
var nominatorSum = (dynamic)a.Nominator + b.Nominator;
var denominatorSum = (dynamic)a.Denominator + b.Denominator;
return new Racional<T>(nominatorSum, denominatorSum);
}
The operator will throw if the type doesn't have a suitable addition operator.
Method #2: Another (more efficient) way is to use expression-trees.
First, create and cache a delegate that can perform the addition by compiling the appropriate expression:
private readonly static Func<T, T, T> Adder;
static Racional()
{
var firstOperand = Expression.Parameter(typeof(T), "x");
var secondOperand = Expression.Parameter(typeof(T), "y");
var body = Expression.Add(firstOperand, secondOperand);
Adder = Expression.Lambda<Func<T, T, T>>
(body, firstOperand, secondOperand).Compile();
}
(The static constructor will throw if the type doesn't have a suitable addition operator.)
Then employ it in the operator:
public static Racional<T> operator *(Racional<T> a, Racional<T> b)
{
var nominatorSum = Adder(a.Nominator, b.Nominator);
var denominatorSum = Adder(a.Denominator, b.Denominator);
return new Racional<T>(nominatorSum, denominatorSum);
}
The issue here is you are defining an operator for Racional<int> in the class Racional<T>. This is not possible. The types are not the same, you can only define operator for Racional<T>.
Generics cannot express generalization of operators since they are defined only for a certain types. Solution is to create a class and inherit from Racional<int>:
public class IntRacional : Racional<int>
{
public static Racional<int> operator +(IntRacional a, IntRacional b)
{
return new Racional<int>()
{
Nominator = a.Nominator + b.Nominator,
Denominator = a.Denominator + b.Denominator
};
}
}
To solve your issue, you need to provide conversion functions from T to some type where operator+ is defined and vice versa. Assuming Int64 is big enough in most cases, this can be done this way:
public class Racional<T>
{
private T nominator;
private T denominator;
static Converter<T,Int64> T_to_Int64;
static Converter<Int64,T> Int64_to_T;
public static void InitConverters(Converter<T,Int64> t2int, Converter<Int64,T> int2t )
{
T_to_Int64 = t2int;
Int64_to_T = int2t;
}
public T Nominator
{
get { return nominator; }
set { nominator = value; }
}
public T Denominator
{
get { return denominator; }
set { denominator = value; }
}
public Racional(T nominator, T denominator)
{
this.nominator = nominator;
this.denominator = denominator;
}
public static Racional<T> operator *(Racional<T> a, Racional<T> b)
{
return new Racional<T>(
Int64_to_T(T_to_Int64(a.nominator) + T_to_Int64(b.nominator)),
Int64_to_T(T_to_Int64(a.denominator) + T_to_Int64(b.denominator)));
}
// By the way, should this not be * instead of + ???
//
// public static Racional<T> operator *(Racional<T> a, Racional<T> b)
// {
// return new Racional<T>(
// Int64_to_T(T_to_Int64(a.nominator) * T_to_Int64(b.nominator)),
// Int64_to_T(T_to_Int64(a.denominator) * T_to_Int64(b.denominator)));
// }
public override string ToString()
{
return "(" + this.nominator + " " + this.denominator + ")";
}
}
Of course, this has the drawback that you must provide the initialization of those converters somewhere at the program start, should look like this:
Racional<int>.InitConverters(x => (Int64)x, y => (int)y);
In a real program, you may know which possible replacements for T you are going to use. So one can provide those 3 or 4 calls in a static constructor like this:
public static Racional()
{
Racional<int>.InitConverters(x => (Int64)x, y => (int)y);
Racional<short>.InitConverters(x => (Int64)x, y => (short)y);
Racional<Int64>.InitConverters(x => (Int64)x, y => (Int64)y);
}
should be sufficient in most cases. Note that this converter initialization is repeated for all 3 types 3 times again, re-initializing the conversion functions multiple times again. In practice this should not make any trouble.
Can I overload operators for class A in class B in C#? For example:
class A
{
}
class B
{
public static A operator+(A x, A y)
{
...
}
}
No; one of the parameters must be the containing type.
From section §10.10.2 of the language specification (version 4.0):
The following rules apply to binary operator declarations, where T denotes the instance type of the class or struct that contains the operator declaration:
• A binary non-shift operator must take two parameters, at least one of which must have type T or T?, and can return any type.
You should think about why. Here's one reason.
class A { }
class B { public static A operator+(A first, A second) { // ... } }
class C { public static A operator+(A first, A second) { // ... } }
A first;
A second;
A result = first + second; // which + ???
Here's another:
class A { public static int operator+(int first, int second) { // ... } }
Assume this allowed for a moment.
int first = 17;
int second = 42;
int result = first + second;
Per the specification for operator overload resolution (§7.3.2), A.+ will have precedence over Int32.+. We've just redefined addition for ints! Nasty.
No, you can't. error CS0563: One of the parameters of a binary operator must be the containing type
"In each case, one parameter must be the same type as the class or struct that declares the operator" quote from
Documentation on overloading operators.
Generally saying NO, but you can do something like following, if it helps :)
class A
{
public static A operator +(A x, A y)
{
A a = new A();
Console.WriteLine("A+"); // say A
return a;
}
}
class B
{
public static A operator +(A x, B y)
{
A a = new A();
Console.WriteLine("return in:A,B in out:A in class B+"); // say B
return a;
}
public static A operator +(B x, B y)
{
A a = new A();
Console.WriteLine("return in:B,B in out:A in class B +");
return a;
}
// and so on....
}
B b = new B();
A a = new A();
A a1 = new A();
B b1 = new B();
a = b + b1; // here you call operator of B, but return A
a = a + a1; // here you call operator of A and return A
To understand your problem, can i ask why you want to do that? :)