Change variable type dynamicallly - c#

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
}

Related

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

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?

Array of objects - modyfing object's fields C#

I've got such a problem. I'm a beginner in C#.
I have an object array (various classes) and in one place of application I want to modify fields like an age or name. Construction
static Object[] prac = new Object[10];
public static void Main(string[] args)
{
prac[0].age = 21;
}
shouts an error
'object' does not contain a definition for 'age' and no extension method 'age' accepting a first argument of type 'object' could be found
I thought that will be similiar to a Java code, but it isn't. What am I doing wrong?
Regards.
You need to cast your member to the class type that contains the age. I'll just assume that your class name is Person and that is has a age member :
static Object[] prac = new Object[10];
public static void Main(string[] args)
{
((Person)prac[0]).age = 21;
}
Important to note are the brackets : (Person)prac[0] is the cast part, you cast the Object prac[0] to a Person object. The outer brackets ((Person)prac[0]) are there so that the code is taken as a Person object, instead of a regular Object.
First you need to cast the object to the type you're intending to work with.
If you work with type object, it has only a limited amount of properties and methods. To use property age, you first need to cast it to the corresponding type that has that property. For instance something like this:
static Object[] prac = new Object[10];
public static void Main(string[] args)
{
SpecificType myObject = prac[0] as SpecificType; // returns null if not successful
if (myObject != null)
myObject.age = 21;
}
HOWEVER, I'm not convinced you're doing the right thing here. I'd personally avoid type object unless absolutely there would be no other way of doing it (and that is very rare in my code). C# is a strongly-type language and by using object you're prone to errors all over the place.
Object doesn't have property age.
All Object's properties and methods are stated here.
It's an array of objects and as the error message suggests, 'object' does not contain a definition for 'age'
You need to declare your array with the type that has age field or property.And the you can modify it whatever you want. For example:
class Person
{
public string Name { get; set; }
}
You have to use an array of your class instead of Object which is the base type of all classes.
static MyClass[] prac = new MyClass[10];
or you have to cast it:
MyClass mc = (MyClass) prac[0];
mc.age = 21;
Object is the base class for all classes in .Net.
Just cast the required value to the required typed class. Or Create a list with the right type instead of object.

C# reflection get object from type

I have a Type object.
I want to get the object isntance from this type. (just to use the ToString() method from this object).
see:
public class P
{
public string s;
}
class Program
{
static void Main(string[] args)
{
P p = new P();
p.s = "foobar";
Type t = p.GetType();
P p2 = ((t.ToObjet()) as P).s;
Console.WriteLine(p2.s);
}
}
Activator.CreateInstance is what you want.
Type givenType;
var obj = Activator.CreateInstance(givenType);
...
var obj = Activator.CreateInstance(givenType) as GivenType;
EDIT: Based on your edits, the extension method on Type you want (ToObject) is effectively the code above. It must create a new one because you can't be certain the source object still exists and even with the type, you could hit a scenario where that type has multiple instances.
You cannot get the instance back. The type is shared between all the instances, so what you want is impossible.
For example: if you know that something is an integer, you don't know which exactly value it has. (Integer is your type, value is a concrete instance.)
There is no way to do that. One reason is that GetType will return the same Type instance for all instances of the same type.
You can test this like so:
// this will print "True"
Console.WriteLine(object.ReferenceEquals("one".GetType(), "two".GetType()));
Calling GetType on those two different string instances returns the same Type instance, so it is clearly impossible to get one of them back based only on that Type instance.

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 :)

C#: Restricting Types in method parameters (not generic parameters)

I'd like to code a function like the following
public void Foo(System.Type t where t : MyClass)
{ ... }
In other words, the argument type is System.Type, and I want to restrict the allowed Types to those that derive from MyClass.
Is there any way to specify this syntactically, or does t have to be checked at runtime?
If your method has to take a Type type as it's argument, there's no way to do this. If you have flexibility with the method call you could do:
public void Foo(MyClass myClass)
and the get the Type by calling .GetType().
To expand a little. System.Type is the type of the argument, so there's no way to further specify what should be passed. Just as a method that takes an integer between 1 and 10, must take an int and then do runtime checking that the limits were properly adhered to.
Specifying the type be MyClass, or derived from it, is a value check on the argument itself. It's like saying the hello parameter in
void Foo(int hello) {...}
must be between 10 and 100. It's not possible to check at compile time.
You must use generics or check the type at run time, just like any other parameter value check.
You can use the following:
public void Foo<T>(T variable) where T : MyClass
{ ... }
The call would be like the following:
{
...
Foo(someInstanceOfMyClass);
...
}
What you want could theoretically be done with attributes. But this is much clearer (imo) and does exactly the same thing:
public void Foo(MyClass m) {
Type t = m.GetType();
// ...
}
why don't you use
public void foo<t>();
instead?
You can also use an extension method, which will be available for all objects convertible to MyClass:
public static class MyClassExtensions
{
public static void Foo(this MyClass obj)
{
// ...
}
}
And you can use it as if it were an ordinary method of an object:
var x = new MyClass();
x.Foo();

Categories

Resources