Take the following:
class A {}
class B : A {}
class C
{
C()
{
var b = new B();
Foo(b);
Foo2(ref b); // <= compile-time error:
// "The 'ref' argument doesn't match the parameter type"
}
void Foo(A a) {}
void Foo2(ref A a) {}
}
Why does the above compile-time error occur? This happens with both ref and out arguments.
=============
UPDATE: I used this answer as the basis for this blog entry:
Why do ref and out parameters not allow type variation?
See the blog page for more commentary on this issue. Thanks for the great question.
=============
Let's suppose you have classes Animal, Mammal, Reptile, Giraffe, Turtle and Tiger, with the obvious subclassing relationships.
Now suppose you have a method void M(ref Mammal m). M can both read and write m.
Can you pass a variable of type Animal to M?
No. That variable could contain a Turtle, but M will assume that it contains only Mammals. A Turtle is not a Mammal.
Conclusion 1: ref parameters cannot be made "bigger". (There are more animals than mammals, so the variable is getting "bigger" because it can contain more things.)
Can you pass a variable of type Giraffe to M?
No. M can write to m, and M might want to write a Tiger into m. Now you've put a Tiger into a variable which is actually of type Giraffe.
Conclusion 2: ref parameters cannot be made "smaller".
Now consider N(out Mammal n).
Can you pass a variable of type Giraffe to N?
No. N can write to n, and N might want to write a Tiger.
Conclusion 3: out parameters cannot be made "smaller".
Can you pass a variable of type Animal to N?
Hmm.
Well, why not? N cannot read from n, it can only write to it, right? You write a Tiger to a variable of type Animal and you're all set, right?
Wrong. The rule is not "N can only write to n".
The rules are, briefly:
1) N has to write to n before N returns normally. (If N throws, all bets are off.)
2) N has to write something to n before it reads something from n.
That permits this sequence of events:
Declare a field x of type Animal.
Pass x as an out parameter to N.
N writes a Tiger into n, which is an alias for x.
On another thread, someone writes a Turtle into x.
N attempts to read the contents of n, and discovers a Turtle in what it thinks is a variable of type Mammal.
Clearly we want to make that illegal.
Conclusion 4: out parameters cannot be made "larger".
Final conclusion: Neither ref nor out parameters may vary their types. To do otherwise is to break verifiable type safety.
If these issues in basic type theory interest you, consider reading my series on how covariance and contravariance work in C# 4.0.
Because in both cases you must be able to assign value to ref/out parameter.
If you try to pass b into Foo2 method as reference, and in Foo2 you try to assing a = new A(), this would be invalid.
Same reason you can't write:
B b = new A();
You're struggling with the classic OOP problem of covariance (and contravariance), see wikipedia: much as this fact may defy intuitive expectations, it's mathematically impossible to allow substitution of derived classes in lieu of base ones for mutable (assignable) arguments (and also containers whose items are assignable, for just the same reason) while still respecting Liskov's principle. Why that is so is sketched in the existing answers, and explored more deeply in these wiki articles and links therefrom.
OOP languages that appear to do so while remaining traditionally statically typesafe are "cheating" (inserting hidden dynamic type checks, or requiring compile-time examination of ALL sources to check); the fundamental choice is: either give up on this covariance and accept practitioners' puzzlement (as C# does here), or move to a dynamic typing approach (as the very first OOP language, Smalltalk, did), or move to immutable (single-assignment) data, like functional languages do (under immutability, you can support covariance, and also avoid other related puzzles such as the fact that you cannot have Square subclass Rectangle in a mutable-data world).
Consider:
class C : A {}
class B : A {}
void Foo2(ref A a) { a = new C(); }
B b = null;
Foo2(ref b);
It would violate type-safety
While the other responses have succinctly explained the reasoning behind this behavior, I think it's worth mentioning that if you really need to do something of this nature you can accomplish similar functionality by making Foo2 into a generic method, as such:
class A {}
class B : A {}
class C
{
C()
{
var b = new B();
Foo(b);
Foo2(ref b); // <= no compile error!
}
void Foo(A a) {}
void Foo2<AType> (ref AType a) where AType: A {}
}
Because giving Foo2 a ref B would result in a malformed object because Foo2 only knows how to fill A part of B.
Isn't that the compiler telling you it would like you to explicitly cast the object so that it can be sure you know what your intentions are?
Foo2(ref (A)b)
Makes sense from a safety perspective, but I would have preferred it if the compiler gave a warning instead of an error, since there are legitimate uses of polymoprhic objects passed by reference. e.g.
class Derp : interfaceX
{
int somevalue=0; //specified that this class contains somevalue by interfaceX
public Derp(int val)
{
somevalue = val;
}
}
void Foo(ref object obj){
int result = (interfaceX)obj.somevalue;
//do stuff to result variable... in my case data access
obj = Activator.CreateInstance(obj.GetType(), result);
}
main()
{
Derp x = new Derp();
Foo(ref Derp);
}
This won't compile, but would it work?
If you use practical examples for your types, you'll see it:
SqlConnection connection = new SqlConnection();
Foo(ref connection);
And now you have your function that takes the ancestor (i.e. Object):
void Foo2(ref Object connection) { }
What can possibly be wrong with that?
void Foo2(ref Object connection)
{
connection = new Bitmap();
}
You just managed to assign a Bitmap to your SqlConnection.
That's no good.
Try again with others:
SqlConnection conn = new SqlConnection();
Foo2(ref conn);
void Foo2(ref DbConnection connection)
{
conn = new OracleConnection();
}
You stuffed an OracleConnection over-top of your SqlConnection.
In my case my function accepted an object and I couldn't send in anything so I simply did
object bla = myVar;
Foo(ref bla);
And that works
My Foo is in VB.NET and it checks for type inside and does a lot of logic
I apologize if my answer is duplicate but others were too long
Related
I have a class that has a parameterless constructor that I want to remove (or make private)
class C
{
string A { get; set; }
int B { get; set; }
public C() { } //Problem
public C(A a, B b)
{
A = a;
B = b;
}
}
Problem is, the code base is littered with hundreds of expressions such as new C {A = a, B = b}, or new C() { B = b, A = a }, in every conceivable variation, ordering of fields, etc. (I didn't know that the brackets were optional until today).
Is there any automated way of fixing up my code to use the 2 argument constructor? The changes are trivial, but I think I'll go insane if I have to do it manually.
My examples have 5 or 6 arguments, and not all are required, etc.
(The motivation is to make the class immutable. Hiding the parameterless constructor and the public setters is the first step)
I've had a small amount of success with regular expressions (Notepad++'s regex support seems to stop after 4 captures), but writing a complex regex to fix 6 items at a time doesn't actually save me a great deal.
You can use the ability to explicitly specify named arguments in a function call (including a constructor) to fix this relatively easily.
Specifically, you can replace
C() { B = b, A = a }
with
C(B: b, A: a)
and the constructor will behave correctly. This will work regardless of the order of the arguments, so long as they're all either specified or optional.
Here's an entirely different approach you can try:
Do exactly what you want to do to C. Then create a CBuilder class which has all the same properties as a C, but only has a single method:
public C Convert()
{
return new C(this.A, this.B);
}
Then, you just need to do a find/replace on new C() {...}; and change it into (new CBuilder() {...}).Convert();, which would be a single regex replacement.
This doesn't immediately solve the problem, but it does let you refactor freely, and you can make it policy that every time you work on something that uses CBuilder, you replace that instance of it with a C instead. Gradually, you'll refactor all the code, but it won't prevent you from moving forward.
Suggestion: Maybe you could make use of named parameters.
new C {A = 5, B = "tt"} is in the end equivalent to new C(A: 5, B: "tt")
So you could replace all occurences of "A =" into "A:" and "B =" into "B :"
This could be easier with temporary rename of A into NewNameForANotCollidingWithAnything so that you can do massive blind automated and safe replace.
Then replace "new C{...}" into new "C (...)" // this is the most difficult part (I did not try it)
Hope it takes you closer to what you need....
Remove your parameterless constructor completely. The compiler will fail on all it's uses and you can switch to use the 2-parameter version.
Assume I have a class C that inherits from 2 interfaces (I1 and I2). I also have two versions of a method (DoStuff), each taking one of the interfaces as a parameter. If I call DoStuff(C), which one gets called?
interface I1 { ... }
interface I2 { ... }
class C : I1, I2 { ... }
int DoStuff(I1 target) { ... }
int DoStuff(I2 target) { ... }
//What gets called here?
C target = new C()
DoStuff(target)
If I2 derives from I1, I think it's relatively simple - the I2 version gets called. I'm interested in the case where the interfaces are independent.
Assume I can't edit C, I1 or I2. And .NET 2.0 if that makes any difference.
Neither gets called. If your two methods are overloads in the same class, the compiler does not attempt to disambiguate at all. It'll simply not compile your code, saying it's ambiguous between your two overloads as you declared target to be a type that implements both interfaces.
If you declare target to be of one of the interface types, or cast it at call-time (as Jon shows), then there's no ambiguity.
As BoltClock says, it won't compile. However, it's easy to make it do what you want: just use an expression of the type that you want to use for the argument. For example:
C target = new C();
DoStuff((I1) target);
or
C target = new C();
I1 i1 = target;
DoStuff(i1);
Basically without any extra work, the overload resolution steps will find both methods in the candidate set, and determine that neither is "better" than the other, so overload resolution will fail.
There will be an error when you try to compile it:
error CS0121: The call is ambiguous between the following methods or properties: 'DoStuff(I1)' and 'DoStuff(I2)'"
I am going through a book trying to understand Generics with C# and I have come across an example I don't understand. Here is the sample code.
using System;
public class Printer
{
public void Print<T>(T argument)
{
Console.WriteLine(argument.ToString());
}
static void Main(string[] arguments)
{
Printer printer = new Printer();
printer.Print<string>("Hello, World");
Console.WriteLine("Done");
Console.ReadKey();
}
}
What is confusing me is the argument to the Print method. I understand using a generic type placeholder when dealing with a collections such as List<T>. However what I don't understand is how <T> comes into play with a method? Is the code just saying that the type of the parameter passed into the Print() method is just not known at design time and could be anything? Could someone help me decipher this? Thank you.
By declaring your method with a generic type, you make your method more flexible as it can then work with variables of any type you choose, including primitive types (unless you specify where T : class of course).
Another very common example that much better illustrates one use of a generic method is a Swap<T>(T, T) method:
/*
* The ref keywords mean "pass by reference" i.e. modify the variables as they
* were passed into the method.
*
* The <T> in the signature tells the compiler that T is a generic type, in case
* the class itself doesn't already declare T a generic type.
*/
public void Swap<T>(ref T x, ref T y)
{
// Tells the compiler that temp should be of the same type as x and y,
// regardless of what type T may be
T temp = x;
x = y;
y = temp;
}
int x = 3, y = 6;
Swap<int>(ref x, ref y);
Console.WriteLine(x + " " + y);
char a = 'a', b = 'b';
Swap<char>(ref a, ref b);
Console.WriteLine(a + " " + b);
Exactly what you wrote. Generic parameters are also possible at method level. They act exactly like on class level, just the scope of the type parameter is limited to the method.
Is the code just saying that the type of the parameter passed into the Print() method is just not known at design time and could be anything?
That's precisely what it's saying. Now, whenever the compiler finds a reference to a T it will automagically substitute the type that was specified in the instance or method call (if the method is generic). A prime example of that type of method is a pattern I've used (and seen used) many times. It's basically a safe cast from one type to another. The type you want to coerce to is specified as the generic parameter. Example:
var something = SafeCast<int>("123.434"); // something == 123
var somethingElse = SafeCast<int>(23.45f); // somethingElse == 23
var somethingNull = SafeCast<int>(null); // this shouldn't throw but return a null
As the compiler does not know what T is, and T isnt defined at class-level, then the compiler needs to know what to cast the parameters to, thats where the argument comes into play ;)
I'm getting confused with what happens on the stack and heap in respect to value type properties in classes.
My understanding so far:
When you create a class with a structure (value type) like this:
class Foo
{
private Bar _BarStruct;
public Bar BarStruct
{
get {return _BarStruct; }
set {_BarStruct = value; }
}
}
private struct Bar
{
public int Number;
Bar()
{
Number = 1;
}
Bar(int i)
{
Number = i;
}
}
If you create a class instance like so:
Foo fooObj = new Foo();
The stack and heap will look like this:
...where the Bar structure is embeded in the Foo class in the heap. This makes sense to me, but I start to loose it when we consider modifying the Number integer in the BarStruct class, within the Foo Object. For example:
Foo fooObj = new Foo();
fooObj.BarStruct.Number = 1;
As I understand, this should be returning a copy of BarStruct to live on the stack, which means that any changes of a member of BarStruct would not be carried through to the object, which is why the last line above gives an error.
Is this right so far?
If so, my question is, how come an assignment such as this:
fooObj.BarStruct = new Bar(2);
...is valid and changes the heap value? Surely this is just changing the value on the stack?? Also, (by and by) I find it so confusing that you are able to use new on a value type. To me, new is for allocatting on the heap (as per C++) and feels unnatural to be doing this for items on the stack.
So just to re-iterate the question, Am I correct in my assumption of what happens when a property containing a structure is called and why can you assign a new structure to a copy and yet it still changes the reference on the heap?
Really hope this all make sense.
Yell if you need clarification!
Ta,
Andy.
Looking at this assignment:
fooObj.BarStruct = new Bar(2);
The assignment isn't changing the value on the stack - it's calling the setter for the property.
In other words, whereas your first assignment is equivalent to:
fooObj.get_BarStruct().Number = 1; // Bad
the second is equivalent to:
fooObj.set_BarStruct(new Bar(2));
Does that help?
Note that the problematic assignment becomes a non-issue if you make your value type immutable to start with - which helps in general, in fact. Mutable value types are a really bad idea in C#; you can get into no end of trouble with them.
In terms of your expectations of "new" - try not to think in C++, basically. C# isn't C++, and various things (destructors, generics, behaviour during construction) will confuse you if you try to effectively write C++ in C#. A "new" statement creates a new instance of a type, whether that's a value type or a reference type.
I have a method which is taking in a parameter that is a Interface object
like this
private void SomeMethod(InterfaceA IUA)
Inside the method I have a statement like this
ClassD someVar = (ClassD)(((ClassC)((ClassB)IUA)).D);
everything if fine and dandy. However, in certain cases the object IUA might be instance of ClassZ rather than ClassB. So in that case the above line errors out. Is there a way to find out, before doing above statement, that which class does the object really belong to? If i know that before hand then I can have an If statement and do the following
ClassZ someVar = (ClassD)(((ClassC)((ClassZ)IUA)).Z);
I come from java background...In java i know we have getClass() ...what would be the equivalent in .net?
You really shouldn't be writing code like this without good reason.
That said: you can use is
if (a is ClassB)
{
ClassB b = (ClassB)a;
}
else if (a is ClassZ)
{
ClassZ z = (ClassZ)a;
}
...or as:
ClassB b = a as ClassB;
if (b != null)
{
// ...
}
Well, for starters, you're not really supposed to downcast from interface to a class, unless you have a really good reason to do so. If you need ClassD functionality, then your method should receive ClassD, not InterfaceA.
Another thing that confuses me is the multiple downcasting. I use both Java and C# and I've never seen the need to do a multiple cast like that.
Finally, you could use operator "is" to find out whether certain type inherits from a certain class or implements a certain interface, as in
if (IUA is ClassD)
{
// do something
}
You can do
if (someVar is ClassZ)
Which returns TRUE if someVar is-a ClassZ,
or
someVar.GetType ()
to get the actual class
How about
if(IUA is ClassB)
someVar = (IUA as ClassB).B;
elseif (IUA is ClassZ)
someVar = (IUA as ClassZ).Z;
That should work, though you get the mandatory scolding that this is a rather poor architecture.
What is the point of passing the interface if your just going to cast it away? You might want to re-evaluate the design as code like this defeats the purpose of polymorphism.
Also you should not use 'is' to test the type. Since you are going to cast the object anyway you should use 'as' and test for null.
Okay, a few different options here:
The equivalent for Java's getClass() is GetType(); you can use typeof(...) to retrieve the Type object for a type you know at compile-time. This isn't the best way of testing things though, unless you're interested in exact equality.
The equivalent of Java's instanceof operator is the is operator in C#:
if (x is SomeType) ...
This can be used with boxed values to check for value types, too:
if (x is int) ...
A related operator is the as operator, which doesn't return true or false, but a reference of the type specified. The type has to be a nullable type (reference or nullable value type) and the result is the original value but strongly typed as the target type if the value is a reference of an appropriate type, or null otherwise. For instance:
object x = "hello";
string y = x as string; // y = "hello" now
Stream z = x as Stream; // z = null now
In the case where you want to check whether or not a reference is of a particular type, and then use it as a reference of that type, a common pattern is:
object x = GetObjectFromSomewhere();
string y = x as string;
if (y != null)
{
Console.WriteLine(y.Length); // Whatever
}
This is more efficient than the equivalent to what's required in Java:
object x = GetObjectFromSomewhere();
if (x is string)
{
string y = (string) x;
Console.WriteLine(y.Length); // Whatever
}
If it's a bug for the reference to be of the wrong type, just cast - that way you'll get an exception thrown if you've got a bug, which is almost certainly the best course of action at that point.
I don't think it's necessary to cast IUA to ClassB. You're not using any of the ClassB methods as far as I can tell.
You could do something like
If (IUA is ClassB)
//I am class b
However, given that your method is taking an interface, I would question your design if you are looking to get back to the actual concrete type. Can you re-factor to create an interface method that you can use to perform the actions of that method.
From MSDN:
public static void Test (object o)
{
Class1 a;
Class2 b;
if (o is Class1)
{
Console.WriteLine ("o is Class1");
a = (Class1)o;
// do something with a
}
else if (o is Class2)
{
Console.WriteLine ("o is Class2");
b = (Class2)o;
// do something with b
}
else
{
Console.WriteLine ("o is neither Class1 nor Class2.");
}
}
You should use method overloading, this is how it should look:
private void SomeMethod(ClassB obj) {
DoMoreStuff(obj.B);
}
private void SomeMethod(ClassZ obj) {
DoMoreStuff(obj.Z);
}
private void DoMoreStuff(int val) {
// ..
}