Do C# generics prevent autoboxing of structs in this case? - c#

Usually, treating a struct S as an interface I will trigger autoboxing of the struct, which can have impacts on performance if done often. However, if I write a generic method taking a type parameter T : I and call it with an S, then will the compiler omit the boxing, since it knows the type S and does not have to use the interface?
This code shows my point:
interface I{
void foo();
}
struct S : I {
public void foo() { /* do something */ }
}
class Y {
void doFoo(I i){
i.foo();
}
void doFooGeneric<T>(T t) where T : I {
t.foo(); // <--- Will an S be boxed here??
}
public static void Main(string[] args){
S x;
doFoo(x); // x is boxed
doFooGeneric(x); // x is not boxed, at least not here, right?
}
}
The doFoo method calls foo() on an object of type I, so once we call it with an S, that S will get boxed. The doFooGeneric method does the same thing. However, once we call it with an S, no autoboxing might be required, since the runtime knows how to call foo() on an S. But will this be done? Or will the runtime blindly box S to an I to call the interface method?

void doFooGeneric<T>(T t) where T : I {
t.foo(); // <--- Will an S be boxed here??
}
Boxing will be avoided there!
The struct type S is sealed. For value type versions of the type parameter T to your method doFooGeneric above, the C# compiler gives code that calls the relevant struct member directly, without boxing.
Which is cool.
See Sameer's answer for some technical details.
OK, so I came up with an example of this. I will be interested in better examples if anyone has some:
using System;
using System.Collections.Generic;
namespace AvoidBoxing
{
static class Program
{
static void Main()
{
var myStruct = new List<int> { 10, 20, 30, }.GetEnumerator();
myStruct.MoveNext(); // moves to '10' in list
//
// UNCOMMENT ONLY *ONE* OF THESE CALLS:
//
//UseMyStruct(ref myStruct);
//UseMyStructAndBox(ref myStruct);
Console.WriteLine("After call, current is now: " + myStruct.Current); // 10 or 20?
}
static void UseMyStruct<T>(ref T myStruct) where T : IEnumerator<int>
{
myStruct.MoveNext();
}
static void UseMyStructAndBox<T>(ref T myStruct)
{
((IEnumerator<int>)myStruct).MoveNext();
}
}
}
Here the type of myStruct is a mutable value-type which holds a reference back to the List<>, and also holds "counter" that remembers what index in the List<> we have reached until now.
I had to use ref, otherwise the value-type would be copied by value when passed into either of the methods!
When I uncomment the call to UseMyStruct (only), this method moves the "counter" inside our value type one position ahead. If it did that in a boxed copy of the value type, we would not see it in the original instance of the struct.
To see what the difference is with boxing, try the call UseMyStructAndBox instead (comment UseMyStruct again). It creates a box at the cast, and the MoveNext happens on a copy. So the output is different!
To those who are unhappy with (or confused by) the ref, just write out Current from within the method instead. Then we can get rid of ref. Example:
static void F<T>(T t) where T : IEnumerator<int>
{
t.MoveNext(); // OK, not boxed
Console.WriteLine(t.Current);
}
static void G<T>(T t) where T : IEnumerator<int>
{
((IEnumerator<int>)t).MoveNext(); // We said "Box!", it will box; 'Move' happens to a copy
Console.WriteLine(t.Current);
}

Boxing will be avoided as Constrained Opcodes come to play in the second case.

Related

Generic class with overridden method - which gets called?

I have a class that overrides the addition operator twice. One that takes the type parameter and one that takes a double:
public class A<T>
{
public A() { }
public static A<T> operator +(A<T> a, T t)
{
Console.WriteLine("Generic add called.");
return new A<T>(); // return to keep the compiler happy
}
public static A<T> operator +(A<T> a, double d)
{
Console.WriteLine("Double add called.");
return new A<T>(); // return to keep the compiler happy
}
}
When the class is parameterized by the int type, it behaves as expected:
A<int> aInt = new A<int>();
var test = aInt + 3;
// -> Generic add called.
test = aInt + 3.0;
// -> Double add called.
But when parameterized by the double type, the non-generic add is called:
A<double> aDouble = new A<double>();
var otherTest = aDouble + 3.0;
// -> Double add called.
Assuming this behavior is the norm, I know which will be called. The non-generic override will be preferred. That said...
Will the non-generic method be always be preferred in the event of a collision?
All of the above code is available, runnable in your browser, here
EDIT: This question is related, but it's asking about generic methods, not classes. He gives this code:
class A
{
public static void MyMethod<T>(T myVal) { }
public static void MyMethod(int myVal) { }
}
which does not apply to my usage examples. Distinguishing between a.MyMethod(3) and a.MyMethod<int>(3) is obvious - one is generic and one is not.
The more specific method will be chosen, but that construction is a bad idea because it is technically unspecified behaviour.
To quote #EricLippert, substituting the code snippets for the ones from my question:
But the situation with [aDouble + 3.0] is far worse. The CLR rules make this sort of situation "implementation defined behaviour" and therefore any old thing can happen. Technically, the CLR could refuse to verify a program that constructs type [A<double>]. Or it could crash. In point of fact it does neither; it does the best it can with the bad situation.
Are there any examples of this sort of type construction causing truly implementation-defined behaviour?
Yes. See these articles for details:
http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx
http://blogs.msdn.com/b/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx
Simple answering yes. The compiler assume that because you have treated by hand a particular type parameter, that means that it has some special logic for you. That's why the second operator is called. To say further, operators are nothing more than static methods that accepts some parameters. For your case it's a binary operator so the static method has two parameters.

How to call overridden method which have overloads?

I have the following simple code
abstract class A
{
public abstract void Test(Int32 value);
}
class B : A
{
public override void Test(Int32 value)
{
Console.WriteLine("Int32");
}
public void Test(Double value)
{
Test((Int32)1);
}
}
When I ran this code the line Test((Int32)1) causes stack overflow due to infinite recursion. The only possible way to correctly call proper method (with integer parameter) I found is
(this as A).Test(1);
But this is not appropriate for me, because both methods Test are public and I am willing the users to be able to call both method?
Method overload resolution in C# does not always behave as you might expect, but your code is behaving according to the specification (I wrote a blog post about this a while ago).
In short, the compiler start off by finding methods that
Has the same name (in your case Test)
are declared in the type (in your case B) or one of its base types
are not declared with the override modifier
Note that last point. This is actually logical, since virtual methods are resolved in run-time, not compile time.
Finally, if the type (in this case B) has a method that is a candidate (which means that the parameters in your call can be implicitly converted to the parameter type of the candidate method), that method will be used. Your overridden method is not even part of the decision process.
If you want to call your overridden method, you will need to cast the object to its base type first.
Unfortunately in order to call the A::Test(int) through a B reference some sort of cast is needed. So long as the C# compiler sees the reference through B it will pick the B::Test(double) version.
A slightly less ugly version is the following
((A)this).Test(1);
Another thought though is have a private method with a different name that both feed into.
class B : A {
public override void Test(int i) {
TestCore(i);
}
public void Test(double d) {
TestCore(1);
}
private void TestCore(int i) {
// Combined logic here
}
}

Can I use some other class's function as a delegate?

Say I have 2 classes, class A and class B. Class A creates an instance of Class B. Class A has a function that I would like to pass into a method from Class B.
class A {
void Main(string[] args) {
B classB=new B();
DelegateCaller(new delFunction(classB.TheFunction()); // <-- Won't compile (method name expected)
DelegateCaller(new delFunction(B.TheFunction()); // <-- Won't compile (object reference is req'd)
}
public delegate string delFunction();
public DelegateCaller(delFunction func) {
System.Console.WriteLine(func());
}
}
class B {
public string TheFunction() {
return "I'm Printing!!!";
}
}
I'm not sure if it a syntax issue or it's just something I can't do. Maybe I need to define the delegate in B, but reference it in A? What about B's this pointer?
It's just a syntax issue; get rid of the parentheses after classB.TheFunction - they indicate that you wish to invoke the method.
DelegateCaller(new delFunction(classB.TheFunction));
Do note that there is an implicit conversion available from a method-group, so you can just do:
DelegateCaller(classB.TheFunction);
Also note that creating your own delegate-type in this case is unnecessary; you could just use the in-built Func<string> type.
EDIT: As Darin Dimitrov points out, there is also the unrelated issue of calling an instance method as though it were a static method.
Try like this:
class A
{
static void Main()
{
B classB = new B();
DelegateCaller(classB.TheFunction);
}
public delegate string delFunction();
public static void DelegateCaller(delFunction func)
{
Console.WriteLine(func());
}
}
class B
{
public string TheFunction()
{
return "I'm Printing!!!";
}
}
Let me elaborate about the different changes I've made to your initial code:
TheFunction in class B needs to be public so that you can access it from class A
The DelegateCaller method in class A should be static and not necessarily return a value (declare it as void) if you want to call it from the static Main method.
The definition of the delFunction delegate should return a string.
Take the parenthesis off the end of TheFunction. You want the method, not the result of a call to the method.
If you want to capture an instance method for usage in a general purpose fashion you should use Delegate.CreateDelegate(Type,MethodInfo). This is nice as it allows you to create an "open delegate" meaning it isn't bound to an instance and can take any instance that is a ClassB. It makes reflection quite fast if you know the type information, as this method will perform much faster than the equivalent statement using MethodInfo.Invoke.
DelegateCaller(new delFunction(B.TheFunction());
Should be
DelegateCaller(new delFunction(B.TheFunction);
To use classB.TheFunction you would need to make TheFunction static. You pass in the function with no parens.

Why can delegates can be used interchangeably for Class methods and Static functions?

I've been using delegates for many years, and haven't really given them much thought.
But I recently got egg on my face by assuming that delegates stored a this reference when referencing a class method.
The below example illustrates the gap in my understanding.
public class SomeClass
{
public SomeClass(int someProperty)
{
SomeProperty = someProperty;
}
public int SomeProperty
{
get;
set;
}
// Throw in a Member field into the mix
public int ClassAdd(int x, int y)
{
return x + y + SomeProperty;
}
}
public static class SomeStaticClass
{
public static int StaticAdd(int x, int y)
{
return x + y;
}
}
Why is it that I can add both static and instance subscribers?
class TestClass
{
delegate int myAddDelegate(int x, int y);
private void UseDelegates()
{
myAddDelegate algorithm;
algorithm = new SomeClass(3).ClassAdd;
// Surprised that I could add static methods to my delegate?
algorithm += SomeStaticClass.StaticAdd;
// I'm fine with just one of the results being returned.
int answer = algorithm(5, 10);
}
}
What is actually going on? ;)
If you create a delegate referring to an instance method, it will capture this (or the relevant reference) in the field backing the Target property of the delegate. If you create a delegate referring to a static method, the Target will be null. Logically there's no need to have an instance if you're using a static method.
As one added complications, you can capture extension methods as if they were instance methods on the extended type:
static class Extensions
{
public static void Foo(this string x)
{
Console.WriteLine("Calling Foo on " + x);
}
}
class Test
{
static void Main()
{
Action action = "text".Foo;
Console.WriteLine(action.Target); // Prints "text"
}
}
As for why you can do all of this: because it's useful, and there's no reason not to allow you to do it :)
There are no static functions in C#, they are actually static methods (so there are static and instance methods). Every delegate basically is pointer to method and this pointer on which the method will be executed, it is Target property of delegate. In case of static method it will be null. Since delegate carry reference to objects it can cause memory leaks if you forget to unsubscribe.
The beauty of delegates is that they just work, for both static and instance methods. If you assign a static method to a delegate, the static method is simply used as-is, since it doesn't need any non-static context to work. For instance methods, a reference to the instance is stored along the method pointer, so that the necessary context (the this reference) is available when the method is called. This means that when you assign an instance method to a delegate, you must also provide an instance - either by specifying it explicitly, or by assigning to the delegate from inside an instance context.
Most of the time, this 'just works', and you don't need to think about anything. There is one caveat though: If you assign an instance method to a delegate, you create another reference to the instance, and as long as the method remains assigned to the delegate (or subscribed to an event), there will also be a reference to the instance, so the GC will never collect it. This is why you should always unsubscribe from all events when cleaning up after yourself.

Why are C# calls different for overloaded methods for different values of the same type?

I have one doubt concerning c# method overloading and call resolution.
Let's suppose I have the following C# code:
enum MyEnum { Value1, Value2 }
public void test() {
method(0); // this calls method(MyEnum)
method(1); // this calls method(object)
}
public void method(object o) {
}
public void method(MyEnum e) {
}
Note that I know how to make it work but I would like to know why for one value of int (0) it calls one method and for another (1) it calls another. It sounds awkward since both values have the same type (int) but they are "linked" for different methods.
Literal 0 is implicitly convertible to any enum type, which is a closer match than object. Spec.
See, for example, these blog posts.
I'm pretty sure to call
public void method(MyEnum e) {
}
properly you need to pass in MyEnum.Value1 or MyEnum.Value2. Enum != int type, hence why you have to cast the int to your enum type. So (MyEnum)1 or (MyEnum)0 would work properly.
In your case, 0 was implicitly cast to your enum type.
Why does C# allow implicit conversion of literal zero to any enum? is a good reference that has a great answer by JaredPar in it.

Categories

Resources