Why can't I convert from 'out BaseClass' to 'out DerivedClass'? - c#

I just learned that having a generic argument as the type of an out parameter forces that generic type to be invariant. This is surprising to me. I thought out parameters are treated the same as return types (i.e. if the generic parameter is covariant, then it can be used in as an out out parameter), since they are both "outputs" of a method.
After a bit of investigation, I realised that you can't do this:
public class Program {
public static void Main() {
// cannot convert from 'out object' to 'out string'
F(out object s); // passing an out object
}
public static void F(out string o) {
o = null;
}
}
This explains why out parameters must be invariant. However, I still don't understand why you can't do this. As is commonly known, out parameters are just another way of returning a value. F could be rewritten with a return value, and it will work:
// This is the semantically equivalent version of the above, just without "out"
public class Program {
public static void Main() {
object s = F();
}
public static string F() {
return null;
}
}
So why doesn't the first code snippet compile? Does using out allow F to do something that can't be done with return values, that will break type-safety if an out object s were passed to it?
I found this question, which is about converting the other way - from a derived class to a base class, which clearly isn't possible. You can't assign the return value of a method that returns a object to a variable of type string, can you?
What I'm asking is, since you can assign the return value of a method that returns string to a variable of type object, why can't you do the same with out parameters? That is, why can't you pass an out object to a out string parameter?
I also read the docs and the spec, but they never mentioned anything about the fact that you have to pass the exact same type into a out parameter, let alone explain why you have to do it.

With out parameters the argument is passed by reference just like ref, the difference is that the value must be assigned by the end of the method and the reference does not need to be initialized before calling. But it can be initialized before and the method can read the initial value.
From the docs: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier
The out keyword causes arguments to be passed by reference
It is like the ref keyword, except that ref requires that the variable be initialized before it is passed
As the method can read the variable, the reference must be of type string to work. The reading blocks covariance and the output blocks contravariance, thus the argument must be invariant.

As is commonly known, out parameters are just another way of returning a value
Not true: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out
As a parameter modifier, which lets you pass an argument to a method by reference rather than by value.
That means that you are passing on a reference to a specific object.
I think your answer though is here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref
Passing a reference type by reference enables the called method to replace the object to which the reference parameter refers in the caller.
So when you are passing an object to the function you are effectively doing an assignment of type
derived <- base
and when you are assigning from inside the function
base <- derived

Think about that you can do something like this in c#:
public static void Out(out string s)
{
Thread.Sleep(50);
s = "World";
}
public static void Ref(ref string s)
{
Console.WriteLine(s); // Hello
Thread.Sleep(100);
Console.WriteLine(s); // World
}
string str = "Hello";
new Thread(() => Out(out str)).Start();
new Thread(() => Ref(ref str)).Start();
If it is legal to change string str to object str, now str can be any type, how to keep the reference between Out and Ref method?

Related

Change variable type dynamicallly

I have an argument in my function which is an object. I would like to change the type of this object in order to have access to the class methods (string, int ...).
I know the convert methods and casts. But I want to keep the same argument name. Like :
public void MyFunction(object test)
{
SpecialConvertFunctionToString(test) // Now test is a string
test.Contains(...) // I can use string methods on
}
I don't know if it's possible ! Thanks !
You can do a cast as or is and then compare.
This will check if test is of type MyClass. If it is, then it casts it as this type into the variable myclassobj. Then you can use the methods, properties of MyClass as normal
if (test is MyClass myclassobj)
{
myclassobj.Name = "new name";
myclasssobj.ExecuteMyMethod();
//etc
}

C# - Need Help Understanding the Lambda Operation and <T> [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I'm currently working on a project, and need a method to get me a variable's name. (XmlNode type). I found this solution - but I have no clue how it works. Any explanation would be helpful. Thank you!
static void Main(string[] args)
{
GetName(new { var1 });
GetName2(() => var1);
}
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
static string GetName2<T>(Expression<Func<T>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
In particular, I don't understand why the parameter is (new {var1}) and (() => var1) when calling the methods, what <T>(T item) where T : class means, and what <T>(Expression<Func<T>> expr) means.
I did read about the lambda operation and <T>, but that doesn't really help that much.
First, the nameof operator was introduced in, I believe, c# 6. It can do what you want. You use it like this:
var myVariable = new Object();
var myVariableName = nameof(myVariable);
Now to unpack your question.
What is (new {var1})?
Here you are calling the GetName method. That method takes a single parameter. The object being passed to the method in this case is instantiated with this code: new { var1 }. Here new { var1 } is creating an anonymous type. The object being created has a single property named 'var1' whose value is the variable var1. Because a property name was not supplied the property was automatically given the same name as the variable. You could have explicitly named the property when you declared the anonymous type like this: new { var1 = var1 }. Or you could have given your property a completely different name: new { DifferentName = var1 } (but this would cause GetName to return the wrong result - see below). If you were to explicitly define these types as classes they would look something like these, respectively:
public class MyClass<T>
{
public MyClass(T property)
{
var1 = property;
}
public var1 { get; }
}
and this:
public class MyClass<T>
{
public MyClass(T property)
{
DifferentName = property;
}
public DifferentName { get; }
}
What is <T>(T item) where T : class?
The <T> in GetName<T> or GetName2<T> is a generic type parameter (generics). In this case it allows you to delay the type specification of the method parameter until the method is invoked. So if I had a method with this signature, for example, MyMethod<T>(T item) I could later call it with an int like this MyMethod<int>(2) or a string like this MyMethod<string>('some string'). Here I am explicitly specifying the type with <int> and <string>. In many cases, when the type is unambigous, you can exclude the type declaration and C# will infer it. So I could do this MyMethod('some string') and C# will be able to infer the type is string. That is what is happening here: GetName(new { var1 }). Since new { var1 } is an anonymous type there is no way to explicitly specify the type when calling GetName. But you can still call GetName with an anonymous type simply by allowing C# to infer the type.
The where T : class portion of the method signature is just a generic constraint, i.e. a constraint is being placed on the types that can be passed to this method. In this case the constraint is that T must be a class and not a value type.
How does GetName<T> work?
This function is using reflection to inspect the object that was passed to it. Here is what is going on: typeof(T) gets the type of object that was passed (remember we are passing an anonymous type), GetProperties() gets all the properties of the type - this will give you an array of PropertyInfo, [0] gives you the first property in that array (in the case where new { var1 } is passed to this method the object will only have a single property named 'var1'), and finally Name gives you the name of that property.
This method is making assumptions about the object being passed to it. Specifically that the object passed has at least 1 property and that the name of the the first property has the same name as the variable whose name we are interested in. This method is far from foolproof, it could easily be broken at runtime by passing an object with no properties, or you could get back the wrong name if you failed to pass an object that conformed to the assumptions that GetName is making.
Interestingly, GetName could have been implemented without generics like this:
static string GetName3(object item)
{
return item.GetType().GetProperties()[0].Name;
}
Perhaps the author was attempting to take advantage of at least a tiny bit of compile time checking by eliminating an entire class of objects (value types) that have no properties from being passed to the method.
What is (() => var1)?
This is an expression. This particular expression represents a function that takes no parameters () and returns an object. I know that from the method signature of GetName2:
GetName2<T>(Expression<Func<T>> expr)`
See, the expr parameter is an Expression of type Func (a function) that takes no parameters and returns a on object of type T.
How does GetName2<T>(Expression<Func<T>> expr) work?
Well... the short and probably not very accurate answer is that it is returning the right side of the expression. So you pass in () => var1 and you get back var1. Let's just leave it at that for now.
new {var1} creates an anonymous object
(() => var1) is a lambda function with no parameters shorthand for:
delegate void () { return var1;}
<T>(T item) where T : class is reflection and constraining the generic
parameter to a class. See DarkSquirrel42 answer

Most efficient way to check if an object is a value type

WARNING: THIS CODE SUCKS, SEE ANTHONY'S COMMENTS
Which is faster?
1.
public bool IsValueType<T>(T obj){
return obj is ValueType;
}
2.
public bool IsValueType<T>(T obj){
return obj == null ? false : obj.GetType().IsValueType;
}
3.
public bool IsValueType<T>(T obj){
return default(T) != null;
}
4.Something else
You aren't really testing an object - you want to test the type. To call those, the caller must know the type, but... meh. Given a signature <T>(T obj) the only sane answer is:
public bool IsValueType<T>() {
return typeof(T).IsValueType;
}
or if we want to use an example object for type inference purposes:
public bool IsValueType<T>(T obj) {
return typeof(T).IsValueType;
}
this doesn't need boxing (GetType() is boxing), and doesn't have problems with Nullable<T>. A more interesting case is when you are passing object...
public bool IsValueType(object obj);
here, we already have massive problems with null, since that could be an empty Nullable<T> (a struct) or a class. But A reasonable attempt would be:
public bool IsValueType(object obj) {
return obj != null && obj.GetType().IsValueType;
}
but note that it is incorrect (and unfixable) for empty Nullable<T>s. Here it becomes pointless to worry about boxing as we are already boxed.
My first answer would be to write a simple test and find out for yourself.
My second answer (without any testing on my part, of course) would be option 1. It is the simplest check. The second method involves two separate checks while the third involves creating a default instance of a type.
You should also consider readability. The framework already gives you the ability to have the following in your code:
if(someObj is ValueType)
{
// Do some work
}
Why even bother creating a method that would simply turn the above statement into (assuming you made your method static and allowed the compiler to infer the generic type):
if(IsValueType(someObj))
{
// Do some work
}
Defining a struct actually defines two types: a value type, and a class type which derives from System.ValueType. If a request is made to create a variable, parameter, field, or array (collectively, 'storage location') of a type which derives from System.ValueType, the system will instead create a storage location which will store the object's fields rather than storing a reference to an object in which those fields appear. On the other hand, if a request is made to create an instance of a type deriving from System.ValueType, the system will create an object instance of a class which derives from System.ValueType.
This may be demonstrated by creating a struct which implements IValue:
interface IValue {int value {get; set;}};
struct ValueStruct : IValue
{
public int value {get; set;}};
}
with generic test routine and code to wrap it:
static void Test<T>(T it) where T:IValue
{
T duplicate = it;
it.value += 1;
duplicate.value += 10;
Console.WriteLine(it.value.ToString());
}
static void Test()
{
ValueStruct v1 = new ValueStruct();
v1.value = 9;
IValue v2 = v1;
Test<ValueStruct>(v1);
Test<ValueStruct>(v1);
Test<IValue>(v1);
Test<IValue>(v1);
Test<IValue>(v2);
Test<IValue>(v2);
}
Note that in every case, calling GetType on the parameter passed to Test would yield ValueStruct, which will report itself as a value type. Nonetheless, the passed-in item will only be a "real" value type on the first two calls. On the third and fourth calls, it will really be a class type, as demonstrated by the fact that a change to duplicate will affect it. And on the fifth and sixth calls, the change will be propagated back to v2, so the second call will "see" it.
static class Metadata<T>
{
static public readonly Type Type = typeof(T);
static public readonly bool IsValueType = Metadata<T>.Type.IsValueType;
}
//fast test if T is ValueType
if(Metadata<T>.IsValueType) //only read static readonly field!
{
//...
}
There are two rules:
1-All Classes are reference types such as Object and String, so it's supported by .NET Framework classes.
2-All structures are value types such as bool and char, even though it contain reference member, so it's supported by .NET Framework structures.
Simply right click on any type and Go To Definition if it's a Class so that means it a reference type else if it's a Struct so that means it's a value type :)
You can use
obj.GetType().IsValueType
This uses reflection but clear way instead of care of boxing unboxing.

Dynamic type in method parameter

I am passing in a dynamic type into a method and having some issues running the code. Wondering if you are able to pass a dynamic object into as a parameter using the out keyword.
Below is the code.
dynamic btApp = AutomationFactory.CreateObject("Test.Application");
dynamic btMessages;
dynamic btFormat = btApp.Formats.Open("c:\\Temp/Format1.btw", false, "");
btFormat.SetNamedSubStringValue("testing", "testtest");
btFormat.Print("Job1", true, -1, out btMessages);
btFormat.Close(2);
issue is in the print method. where the last argument is passing in a dynamic object.
When you pass a out parameter to a method with a variable that is of type dynamic the parameter itself must be of type dynamic. The following code is legal:
class Program {
static void Main(string[] args) {
dynamic value;
SomeMethod(out value);
return;
}
static void SomeMethod(out dynamic value) {
value = "5";
return;
}
}
In fact SomeMethod can assign anything to value. When the parameter is not of type dynamic then the compiler attempts to convert before the method call, which is not permitted, so if the parameter in SomeMethod is anything but dynamic, your out of luck.
It depends on what the actual type signature of the Print method is. The dynamic type is represented as object at runtime, so if the Print method takes an out parameter of type object (or dynamic), then it should work.
If the Print method has actual out parameter of some other type, then the actual runtime type used at the side of the caller doesn't match the actual type of the declaration, so it will not work.

Passing Delegate object to method with Func<> parameter

I have a method Foo4 that accepts a parameter of the type Func<>. If I pass a parameter of anonymous type , I get no error. But if I create and pass an object of the type 'delegate' that references to a Method with correct signature, I get compiler error. I am not able to understand why I am getting error in this case.
class Learn6
{
delegate string Mydelegate(int a);
public void Start()
{
Mydelegate objMydelegate = new Mydelegate(Foo1);
//No Error
Foo4(delegate(int s) { return s.ToString(); });
//This line gives compiler error.
Foo4(objMydelegate);
}
public string Foo1(int a) { return a.ToString();}
public void Foo4(Func<int, string> F) { Console.WriteLine(F(42)); }
}
It works if you pass a reference to the method directly:
Foo4(Foo1);
This is because actual delegates with the same shape are not inherently considered compatible. If the contracts are implicit, the compiler infers the contract and matches them up. If they are explicit (e.g. declared types) no inference is performed - they are simply different types.
It is similar to:
public class Foo
{
public string Property {get;set;}
}
public class Bar
{
public string Property {get;set;}
}
We can see the two classes have the same signature and are "compatible", but the compiler sees them as two different types, and nothing more.
Because Func<int, string> and MyDelegate are different declared types. They happen to be compatible with the same set of methods; but there is no implicit conversion between them.
//This line gives compiler error.
Foo4(objMydelegate);
//This works ok.
Foo4(objMydelegate.Invoke);
depends on the scenario, but in the general case there's no reason to keep around the Mydelegate type, just use Func<int, string> everywhere :)

Categories

Resources