Applying operators to non-mathematical objects? - c#

I'm curious about how some operators work (+, -) in terms of objects.
I've always wondered how EventHandlers work by adding a method:
Foo.Action += new FooActionHandler
If not an Event, what about returning a comparison?
DateTime - DateTime
That returns a TimeSpan object, and I'm a bit baffled as to how that's possible. I use these kinds of methods all the time but I've never understood the inner workings of them. How would I create my own class to do something like this?

You can overload operators to perform whatever action you want. Here is some good documentation for how to do it in C#.
The gist of it is that you provide a context for the operator (your class) and what occurs with the parameters to it. A sample might look like this:
// Overload '+' for my class
public static MyClass operator +(MyClass c1, MyClass c2)
{
MyClass newMyClass = new MyClass();
newMyClass.MyIntProperty = c1.MyIntProperty + c2.MyIntProperty;
return newMyClass;
}

You can define operators like this:
public static MyClass operator +(MyClass a, MyClass b) { }
With the same syntax for -, *, etc.
Here are some tips (my opinion, mostly):
Don't put the actual logic in the operator - create a static method.
// NOT
public static MyClass operator +(MyClass a, MyClass b) { /* ... */ }
// YES
public static MyClass Add(MyClass a, MyClass b) { return new MyClass(a.Prop + b.Prop); }
public static MyClass operator +(MyClass a, MyClass b) { return Add(a, b); }
Don't bend the operators to do something they shouldn't - ie, don't use + to add to a list, or - to remove from a list, for example.
This causes two problems:
It isn't very well-regarded in the community
The compiler won't catch errors if you accidentally add two objects.

This is called operator overloading. Google will return many articles that explain how it works, and when to use and not use it.
http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=88

Here ya go: http://msdn.microsoft.com/en-us/library/aa288467(VS.71).aspx

It is called operator overloading. C# allows you to overload select operators.
There is more information on this here.

You can overload an operator to do whatever you want.
Lets say I have a Truck Class, and MachineGun class, I want to be able to do this:
Transformer myTransformer = mytruck + myGun;

the += and -= for EventHandlers are shortcuts for Delegate.Combine and Delegate.Remove, this is accomplished with operator overloading, see this site for more details.

This is known as operator overloading. It's used by the framework extensively, however you should avoid doing it since it can lead to some bad code if you don't know what you're doing.
Most programmers don't expect to see a custom class with operators being overloaded so it can become maintenance hell when other programmers have to look at your code and figure out what is going on.
Of course, there are situations where you may find it useful, but usually you're better off just using methods instead of creating operator overloads. You can find out more info from Microsoft here:
http://msdn.microsoft.com/en-us/library/aa288467.aspx

Plenty of answers have covered how you do it. Now just remember that you'll almost never want to actually do it yourself. You need to be really sure that anyone using your class will agree with you about what subtracting two MyClass objects means. If it represents some kind of mathematical structure (vector, matrix, etc) then you're probably safe. Otherwise, it's probably unclear. Notice that Microsoft defined subtraction for DateTime, but didn't allow
List<string> myList = new List<string>();
myList += "foo";
Any time you write
static Foo operator -( Foo a, Foo b )
then think about what you'd call that method if you couldn't override subtraction. If the best possible name isn't Subtract, then you probably want to just create a method with that other name.

Related

Explicit and implicit for operator (int)

public static explicit operator int(Author a)
{
return a.Publications.Length;
}
public static implicit operator int(Author a)
{
return a.Publications.Length;
}
why can`t I do this? my teacher asked me to override the implicit and explicit cast for operator int for the Author class. + can I get a explanation for the deep copy :D?
why can`t I do this?
You can't do that because the C# specification says that you cannot, in section 10.10.3.
[...] a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types.
Now you might well say:
Answering a "why" question with "because that's what it says in the spec" is deeply unsatisfying.
You asked a vague question. If you want a more specific answer then ask a more specific question. How about:
What factors might the C# design team have considered when creating this rule?
Any implicit conversion is already a legal explicit conversion. That is, if there is an implicit conversion that allows:
Shape s = whatever;
Fruit f = s;
then
Fruit f = (Fruit)s;
is also legal and must mean the same thing. It would be bizarre if those two statements had different semantics, but in a world where you could declare two different versions of the same conversion, one explicit and one implicit, then the compiler would have to detect this situation and ensure that the right conversion is used.
Conversion logic, particularly user-defined conversion logic, is extremely complex in C#. Removing unnecessary, confusing complications is a good idea.
can I get a explanation for the deep copy
Don't ask two questions in one question. Post a second question if you have a second question.
I suspect your seeing compiler error CS0557.
FYI, if you have an implicit operator there is no need for an explicit too. Implicit means there is no need to do a direct cast.
Explicit:
Author a = new Author();
int i = (int)a;
Implicit:
Author a = new Author();
int i = a;

Interfaces, Inheritance, Implicit operators and type conversions, why is it this way?

I'm working with a class library called DDay ICal.
It is a C# wrapper for the iCalendar System implemented in Outlook Calendars, and many many many more systems.
My question is derived from some work I was doing with this system.
There are 3 objects in question here
IRecurrencePattern - Interface
RecurrencePattern - Implementation of IRecurrencePattern Interface
DbRecurPatt - Custom Class that has an implicit type operator
IRecurrencePattern: Not all code is shown
public interface IRecurrencePattern
{
string Data { get; set; }
}
RecurrencePattern: Not all code is shown
public class RecurrencePattern : IRecurrencePattern
{
public string Data { get; set; }
}
DbRecurPatt: Not all code is shown
public class DbRecurPatt
{
public string Name { get; set; }
public string Description { get; set; }
public static implicit operator RecurrencePattern(DbRecurPatt obj)
{
return new RecurrencePattern() { Data = $"{Name} - {Description}" };
}
}
The confusing part: Through out DDay.ICal system they are using ILists to contain a collection of Recurrence patterns for each event in the calendar, the custom class is used to fetch information from a database and then it is cast to the Recurrence Pattern through the implicit type conversion operator.
But in the code, I noticed it kept crashing when converting to the List<IRecurrencePattern> from a List<DbRecurPatt> I realized that I needed to convert to RecurrencePattern, then Convert to IRecurrencePattern (as there are other classes that implement IRecurrencePattern differently that are also included in the collection
var unsorted = new List<DbRecurPatt>{ new DbRecurPatt(), new DbRecurPatt() };
var sorted = unsorted.Select(t => (IRecurrencePattern)t);
The above code does not work, it throws an error on IRecurrencePattern.
var sorted = unsorted.Select(t => (IRecurrencePattern)(RecurrencePattern)t);
This does work tho, so the question I have is; Why does the first one not work?
(And is there a way to improve this method?)
I believe it might be because the implicit operator is on the RecurrencePattern object and not the interface, is this correct? (I'm new to interfaces and implicit operators)
You have basically asked the compiler to do this:
I have this: DbRecurPatt
I want this: IRecurrencePattern
Please figure out a way to get from point 1. to point 2.
The compiler, even though it may only have one choice, does not allow you to do this. The cast operator specifically says that DbRecurPatt can be converted to a RecurrencePattern, not to a IRecurrencePattern.
The compiler only checks if one of the two types involved specifies a rule on how to convert from one to the other, it does not allow intermediary steps.
Since no operator has been defined that allows DbRecurPatt to be converted directly to IRecurrencePattern, the compiler will compile this as a hard cast, reinterpreting the reference as a reference through an interface, which will fail at runtime.
So, the next question would be this: How can I then do this? And the answer is you can't.
The compiler does not allow you to define a user-defined conversion operator to or from an interface. A different question here on Stack Overflow has more information.
If you try to define such an operator:
public static implicit operator IRecurrencePattern(DbRecurPatt obj)
{
return new RecurrencePattern() { Data = $"{obj.Name} - {obj.Description}" };
}
The compiler will say this:
CS0552
'DbRecurPatt.implicit operator IRecurrencePattern(DbRecurPatt)': user-defined conversions to or from an interface are not allowed
Why does the first one not work?
Because you're asking the runtime for two implicit conversions - one to RecurrencePattern and one to IRecurrencePattern. The runtime will only look for a direct implicit relationship - it will not scan all possible routes to get you ask it to go. Suppose there were multiple implicit conversions to different types of classes that implement IRecurrencePattern. Which one would the runtime choose? Instead it forces you to specify individual casts.
This is documented in Section 6.4.3 of the C# Language specification:
Evaluation of a user-defined conversion never involves more than one
user-defined or lifted conversion operator. In other words, a
conversion from type S to type T will never first execute a
user-defined conversion from S to X and then execute a user-defined
conversion from X to T.
As others have pointed out already, you can't make a direct jump from DbRecurPatt to IRecurrencePattern. This is why you end up with this very ugly double cast:
var sorted = unsorted.Select(t => (IRecurrencePattern)(RecurrencePattern)t);
But, for completeness' sake, it should be mentioned that it is possible to go from a DbRecurPatt to a IRecurrencePattern without any casts with your current design. It's just that to do so, you need to split your expression into multiple statements, and by doing so, the code does become considerably uglier.
Still, it's good to know that you can do this without any casts:
var sorted = unsorted.Select( t => {
RecurrencePattern recurrencePattern = t; // no cast
IRecurrencePattern recurrencePatternInterface = recurrencePattern; // no cast here either
return recurrencePatternInterface;
});
EDIT
Credit to Bill Nadeau's answer for the idea. You can also benefit from implicit conversion and its compile time guarantees while keeping the code pretty elegant by writing it this way instead:
var sorted = unsorted
.Select<DbRecurPatt, RecurrencePattern>(t => t) // implicit conversion - no cast
.Select<RecurrencePattern, IRecurrencePattern>(t => t); // implicit conversion - no cast
There's another path to accomplish what you want. Specifically mark your generic arguments on your method calls instead of letting the compiler infer your generic arguments. You will still avoid casting, and it may be a little less verbose than some of the other options. The only caveat is you must include an additional Linq statement, which will resolve your list, if that matters.
var sorted = unsorted
.Select<DbRecurPatt, RecurrencePattern>(t => t)
.ToList<IRecurrencePattern>();
You could also combine this answer with sstan's to avoid the extra Linq statement.
... and to answer your final question about the implicit operator - no, you can't define an implicit operator on an interface. That topic is covered in more detail in this question:
implicit operator using interfaces

C# class += operator overload

I have a C# script that requires an item to be added or removed from a list. I thought it would be nicer to use += and -= operators.
In C# an operator is done by:
public Foo operator +(Foo A, Foo B){
//Some adding code;
return C;
}
however I only get a syntax error when I attempt:
public SpriteValues operator +=(SpriteValues A){
//Add A to this
return this;
}
I know in python it would be done using:
def __iadd__(self, A):
#Add A to this
return self
So how do I do this in C#?
From here you can't overload += directly but note the comment:
Assignment operators cannot be overloaded, but +=, for example, is evaluated using +, which can be overloaded
So if you only overload the + operator that should be fine
You can't overload the += operator as a += b it is just shorthand for a = a + b.
Overloading the + operator will allow you to use += on your object.
You can't overload +=, but it utilizes the + operator with the assignment, so as long as you override + it should work.
I'd advocate not implementing +/- for these operations. In many cases it will result in confusing usage. Assuming your list is mutable (that's why you want add and remove operations), defining +/- becomes tricky. There are several issues to think about.
One requirement is that + should not cause side effects. It would be very weird if var z = x + y mutated x or y. Therefore, you must create new list inside +/-. Most developers would not expect this to happen and it is going to be very expensive to copy the items every time one is added.
Let's say you can live with copying on every add/remove. What would you expect the state of the program to be after executing this fragment:
var list1 = new MyList();
var list2 = list1;
list2 += item;
Most would expect that list1 and list2 to refer to the same list object that now has item in it. However, since + creates a new list, that is not what happens. list1 is empty and list2 is a different list that contains item. This is very weird.
You either have to drop the requirement that the list is mutable, +/- won't cause side effects, or the expectation that += won't create a new list. Of course, in the framework delegates have these operators and they are immutable. The behavior of +/- for delegates is one of the more confusing parts of the language so I would not advocate that you emulate it.
I would go the normal route of implementing Add/Remove methods who semantics are well-known and can be easily predicted.
Lists are very common, generic classes, and as such have well-known methods by which things can be added to or removed from them (namely Add and Remove).
If you go overloading operators instead you'll just confuse the heck out of the poor guy that will come along and have to maintain your code once you're gone.

What is the C# equivalent of VB.NET CType?

I've tried googling this and am also using the search feature on this site, but none of the answers I've found answer my question.
In Visual Basic, if I wanted an easy way to convert from one of my classes to another custom class, I can define the CType operator to define how to convert from one class to the other. I can then call CType( fromObject, toNewType) to do the conversion or in C# I guess you can just do a simple cast.
However, in C#, how do you define how the actual cast will be handled from one custom class to another to another custom class (like you can in Visual Basic using the CType operator)?
You could define a custom cast using the explicit keyword:
public static explicit operator TargetClass(SourceClass sc)
{
return new TargetClass(...)
}
...but consider not doing that. It'll confuse the folks who will have to maintain your software down the line. Instead, just define a constructor for your target class, taking an instance of your source class as an argument:
public TargetClass(SourceClass sc)
{
// your conversions
}
I think you want the explicit operator
Example from MSDN:
// Must be defined inside a class called Farenheit:
public static explicit operator Celsius(Fahrenheit f)
{
return new Celsius((5.0f / 9.0f) * (f.degrees - 32));
}
Fahrenheit f = new Fahrenheit(100.0f);
Console.Write("{0} fahrenheit", f.Degrees);
Celsius c = (Celsius)f;
You want to overload the Cast operators on a class.
If you do not have any specific code for conversion, System.Convert methods are closest to CType in Visual Basic. Otherwise, it can be seen in light of some example like:
VB.NET
Dim btn As Button = CType(obj, Button)
C# Equivalent:
Button btn = (Button)obj
or
Button btn = obj as Button

Implicit cast operator from object

I was wondering if someone could think of a nice workaround for not being able to add an implicit cast operator, for object, on your own class. The following example illustrates the kind of code I would like
public class Response
{
public string Contents { get; set; }
public static implicit operator Response(object source)
{
return new Response { Contents = source.ToString(); };
}
}
This won't compile because it upsets the C# compiler and it tells me
user-defined conversions to or from a base class are not allowed
Turning response into Response and doing
public static implicit operator Response<T>(T source)
is unfortunately not an option. My guess is going to be no, but could anyone think of a nice workaround/hack to get this to work. I would love to be able to do
public Response Foo()
{
return new Bar();
}
and end up with a Response.Contents that said Whatever.Namespace.Bar
I'm not a fan of implicit conversions like this - other answers have explained why this isn't allowed. One option to make the conversion easy if you really don't want constructor calls in your code is via an extension method:
public static ResponseExtensions
{
public static Response ToResponse(this object source)
{
return new Response { Contents = source.ToString(); };
}
}
Then you can at least have:
public Response Foo()
{
return new Bar().ToResponse();
}
Generally I'm wary of extension methods on object, mind you... does it really make sense to convert any object at all into a Response?
Think about
Response r = CreateSomeExampleResponse();
Response r2 = r;
having the user-defined conversion defined for any of the base classes of Response. What shall happen in the example? The second assignment is ambiguous:
will r2 reference to a new Response instance with Content set to r.ToString() or
will r2 reference to the instance ris referring to?
(okay or will R2 have to do anything with some force, light sabers and stuff)
We can even expand our thoughts to subclasses of Response that are certainly allowed and correct because of polymorphy.
I guess there is no way to accomplish this. Moreover your code perhaps would be nicer to look at, but it would be far away from being well understandable.
I suggest using a the dynamic type instead of implicit object casting. It's basically what dynamic is, seemingly.
Moreover, see this question for the debate on conversions to or from a base class: User-defined conversion operator from base class
However, this was a very specific case where the cast was really needed. You might need to rethink your design instead.
there is no solution to your problem with your costraints. This is clearly specified in the error: user-defined conversions to or from a base class are not allowed. Since every class inherits object, you have your answer. Inheritance from Response to object means that all instances of Response are also instances of object!!! An implicit cast from object to Response means that every object is a Response, which is a nonsense!!!
In your case, could you simply define a Bar -> Response operator?
When you perform type conversion, you must be able to define a conversion algorithm someway. Can you tell me how are you supposed to convert an object, the most generic type in .NET that has only a hash code and a string representation, into an object of a specific type?

Categories

Resources