How to cast implicitly on a reflected method call - c#

I have a class Thing that is implicitly castable from a string. When I call a method with a Thing parameter directly the cast from string to Thing is done correctly.
However if I use reflection to call the same method it throws the exception
System.ArgumentException : Object of type 'System.String' cannot be
converted to type 'Things.Program+Thing'.
Maybe there is a good reason for this, but I can't figure it out. Does somebody have an idea how to get this working using reflection?
namespace Things
{
class Program
{
public class Thing
{
public string Some;
public static implicit operator Thing(string s)
{
return new Thing {Some = s};
}
}
public void showThing(Thing t)
{
Console.WriteLine("Some = " + t.Some);
}
public void Main()
{
showThing("foo");
MethodInfo showThingReflected = GetType().GetMethod("showThing");
showThingReflected.Invoke(this, new dynamic[] {"foo"});
}
}
}
Meta: Please, no discussions why implicit casting or reflection is bad.

The trick is to realize that the compiler creates a special static method called op_Implicit for your implicit conversion operator.
object arg = "foo";
// Program.showThing(Thing t)
var showThingReflected = GetType().GetMethod("showThing");
// typeof(Thing)
var paramType = showThingReflected.GetParameters()
.Single()
.ParameterType;
// Thing.implicit operator Thing(string s)
var converter = paramType.GetMethod("op_Implicit", new[] { arg.GetType() });
if (converter != null)
arg = converter.Invoke(null, new[] { arg }); // Converter exists: arg = (Thing)"foo";
// showThing(arg)
showThingReflected.Invoke(this, new[] { arg });

Found an answer which uses a TypeConverter (as Saeed mentions)
Seems to do the job.
TypeConverter For Implicit Conversion when using reflection

In this specific case you can make the conversion through the array type, that is
showThingReflected.Invoke(this, new Thing[] {"foo"});
but that's a kind of "cheating". In general, you cannot expect the Invoke to consider your user-defined implicit operator. This conversion must be inferred compile-time.

Related

Casting object to type into variable of said type known only at runtime

Can someone help me to understand why the below doesn't work?
void test(int i)
{
Console.WriteLine("int");
}
void test(String s)
{
Console.WriteLine("String");
}
void runMe()
{
object obj = 1;
Type t = typeof(int);
test((t)obj);
}
You get a "The type or namespace name 't' could not be found" error.
Is there a way to make this work? I need to cast an object to a specific type known only at runtime, but all options I've found are simply converting the data but still storing them in an object.
Edit: Added some pseudo methods to give more context.
It looks like you're basically trying to perform dynamic dispatch. The way you're trying it won't work, because while you work with static typing, all overload resolution is performed at execution.
However, you can use dynamic typing for this instead, with the dynamic type. At that point, overload resolution is performed at execution time instead:
void Test(int i)
{
Console.WriteLine("int");
}
void Test(String s)
{
Console.WriteLine("String");
}
void RunMe()
{
dynamic obj = 1;
// The right overload is picked at execution time
Test(obj);
}
That will accomplish what you've shown in your question - but it's not necessarily the best approach. If you can possibly stick to static typing (without using reflection) I would do so. If you can only handle a known set of types, you might want to keep a Dictionary<Type, Action<object>> or something like that... although you then need to consider awkward things like subtyping etc.
If you do use dynamic typing, I'd try to use it for just a small piece of your code. As soon as you can get back "out" of dynamic typing, do so (e.g. by casting the result of a dynamically-bound call to its expected return type).
Here's an example with a few ways to do it combined into one example.
First method is to overload your method for supported types (these can get called directly when type is known at compile-time) and create a catch-all default overloaded method with parameter of type object which internally checks for supported types and calls the appropriate type-specific method (this is for types only known at run-time).
Second method can be used as an extension to the first, but you can also implement just the second method and skip the first part. Since you know the type at the start of the run-time and the type is not expected to change with each call, you can skip the per-call type checking and instead do a check once when you load the config, then set the appropriate delegate.
try it: https://dotnetfiddle.net/06JYE1#
using System;
public class Program
{
public static void Main()
{
var p = new Program();
object s = "Hi";
object i = 42;
object f = 3.14;
p.Test(s);
p.Test(i);
p.Test(f);
p.SetTestType(GetConfigType());
p.ConfiguredTest("Hello");
p.ConfiguredTest(s);
}
public static Type GetConfigType() { return typeof(string); }
Action<object> ConfiguredTest;
void SetTestType(Type type)
{
if (type == typeof(string))
ConfiguredTest = o => Test((string)o);
else if (type == typeof(int))
ConfiguredTest = o => Test((int)o);
else
ConfiguredTest = null;
}
void Test(object o) // catch-all when type is not known until runtime
{
if (ConfiguredTest != null)
{
ConfiguredTest(o); // if type is configured, we can skip type checking
}
else // if type is not configured, check for supported types
{
if (o is string)
Test((string)o);
else if (o is int)
Test((int)o);
else
Console.WriteLine("Unsupported type: " + o.GetType());
}
}
void Test(int i) { Console.WriteLine("Int = " + i); }
void Test(String s) { Console.WriteLine("String = " + s); }
}

Custom return type based on input data

I have a method which takes an interface type and evaluates what the type is and from that I need to return a type related to it. But I'm not sure how to make the type returns flexible for it. I tried something like this:
public static T GridPosition <T>(IReSizeableGrid gridData) {
if (gridData is Hex) {
var hexGrid = (HexGrid) gridData;
return HexLibrary.WorldToHex(WorldPoint(Input.mousePosition, GroundPlane), hexGrid);
}
if (gridData is QuadGrid) {
var quadGrid = (QuadGrid) gridData;
return Grid.Get(WorldPoint(Input.mousePosition, GroundPlane), quadGrid);
}
throw new Exception("Wrong type passed to GridPosition: " + gridData.GetType());
}
But I get this error:
Cannot implicitly convert type Hex to T
Am I on the right lines here using T? Trying to understand how to use it properly.
Sometimes generics aren't the right answer. You'd only use generics if you want to do the same thing to two or more related types. In this case, you are doing completely different things, so you actually need to use method overloading instead.
public static Point GridPosition(HexGrid gridData)
{
return HexLibrary.WorldToHex( WorldPoint( Input.mousePosition, GroundPlane), gridData);
}
public static Point GridPosition(QuadGrid gridData)
{
return Grid.Get(WorldPoint(Input.mousePosition, GroundPlane), gridData);
}
You can call either of these with the same code:
var result = GridPosition(new HexGrid());
var result = GridPosition(new QuadGrid());
...and the compiler will pick the right version for you.
Since Hex and QuadGrid implement IReSizeableGrid, you can make the type of the gridData parameter also T, and then restrict T to IReSizeableGrid:
public static T GridPosition<T>(T gridData) where T : IReSizeableGrid {
if (gridData is Hex) {
var hexGrid = (HexGrid) gridData;
return (T)HexLibrary.WorldToHex(WorldPoint(Input.mousePosition, GroundPlane), hexGrid);
}
if (gridData is QuadGrid) {
var quadGrid = (QuadGrid)gridData;
return (T)Grid.Get(WorldPoint(Input.mousePosition, GroundPlane), quadGrid);
}
throw new Exception("Wrong type passed to GridPosition: "+gridData.GetType());
}
You don't need to specify the type <T> when calling the function. It will be taken from the type of the gridData parameter.

C# cast generic type (like C++ user defined conversions)

Is there a way in C# to perform a user defined conversion for generic types ?
for example:
class Stack<T>
{
private T x; //should be an array but doesn't matter for this example
public Stack(T input)
{
x = input;
}
public Stack<Q> Convert<Q>(Stack<T> inputStack)
{
//what would go here ? The call is below.
}
}
//main code
Stack<int> stack = new Stack<int>(2);
Stack<long> longstack = stack.Convert<long>(stack);
I would imagine that the compiler can deduce that Q is long and T is int in the Convert function, but it doesn't seem to work.
No, because class-level generic type parameters can't be auto-infered from usage.
I would imagine that the compiler can deduce that Q is long and T is
int in the Convert function, but it doesn't seem to work.
Maybe, but at the end of the day, a generic type parameter doesn't belong to constructor. That is, you provide a generic argument to the type based on what constructor parameter/argument? What happens if there're more than a constructor parameter?
public class A<T>
{
// Which one should be used to auto-infer T from usage?
// Maybe the integer? Or the bool? Or just the string...?
// Every choice seems a joke, because it would be absolutely
// arbitrary and unpredictable...
public A(int x, string y, bool z)
{
}
}
Now take your sample code as example. It has the same issue: what argument should be used from your Convert static method to infer generic type argument from usage? What happens if Convert has more than an argument...?
Here is extension method for standart Stack class (you can rewrite it a little and use like instance method in your own Stack class):
public static class MyStackExtensions
{
public static Stack<TDest> Convert<TSrc, TDest>(
this Stack<TSrc> stack,
Func<TSrc, TDest> converter = null)
{
if (stack == null)
throw new ArgumentNullException("stack");
var items = converter == null
? stack.Select(i => (TDest) System.Convert.ChangeType(i, typeof (TDest)))
: stack.Select(converter);
return new Stack<TDest>(items.Reverse());
}
}
Convert stack from int to long using convert function - no type params needed :-)
var intStack = new Stack<int>(new[] { 1, 2, 3 });
var longStack = intStack.Convert(i => (long)i);
Or using standart conversion:
var intStack = new Stack<int>(new[] { 1, 2, 3 });
var longStack = intStack.Convert<int, long>();

Implicit conversions not considered in overload resolution?

I'm trying to wrap a type (outside of my control) so that it would seamlessly appear to implement an interface (also outside of my control).
Given these defintions
// External types. Not changable.
class Foo {
public int I { get; set; }
public int J { get; set; }
}
interface IGenerateSignature {
string Generate();
}
I would like to use a Foo instance to call a method with an IGenerateSignature parameter:
void Test() {
var foo = new Foo { I = 1, J = 2 };
GetSignature(foo);
}
void GetSignature(IGenerateSignature sig) {
Console.Write(sig.Generate());
}
I tried creating an intermediary struct like this:
struct FooSignaturizer : IGenerateSignature {
private readonly Foo _foo;
public FooSignaturizer(Foo f) {
_foo = f;
}
public static implicit operator FooSignaturizer(Foo f) {
return new FooSignaturizer(f);
}
public string Generate() {
return _foo.I + ":" + _foo.J;
}
}
But for some reason overload resolution fails to find the conversion from Foo to FooSignaturizer, and I get a "Cannot convert" compiler error. If I manually add a cast, GetSignature((FooSignaturizer) foo), it works. However, I need to also add support for the Bar and Qux types, with BarSignaturizer and QuxSignaturizer, so the cast won't work for those cases.
Is there a way to accomplish this?
As per 7.5.3.1 of the C# spec, only implicit conversions from argument expression to parameter type are considered.
7.5.3.1 Applicable function member
A function member is said to be an applicable function member with respect to an argument list A when all of the following are true:
Each argument in A corresponds to a parameter in the function member declaration as described in §7.5.1.1, and any parameter to which no argument corresponds is an optional parameter.
For each argument in A, the parameter passing mode of the argument (i.e., value, ref, or out) is identical to the parameter passing mode of the corresponding parameter, and
for a value parameter or a parameter array, an implicit conversion (§6.1) exists from the argument to the type of the corresponding parameter, or
for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter. After all, a ref or out parameter is an alias for the argument passed.
What you have here isn't an implicit conversion from Foo to IGenereateSignature, it's a wrapper.
As an explanation for this behaviour, you can't exect the compiler to go though every implementation of IGenerateSignature in scope to see whether it has an implicit conversion to/from Foo. What if there was more than one?
In terms of how you can achieve this for Foo, Bar and Qux...
What you're trying to achieve, one call to GetSignature(fooOrBarOrQux), isn't possible, because (based on your description of Foo) you can't have one variable that can be a Foo or a Bar or a Qux at compile time - they're unrelated. You'll always need three call sites, so there's no reason not to have three slightly-different conversions (wrapper class or overloaded method call or something) for the three cases.
... unless you use dynamic?
Rawling's answer gives a good explanation of why you have the problem. Since you can't fix this with implicit conversion, you could try extension methods to convert all types to IGenerateSignature like this:
void Test() {
var foo = new Foo { I = 1, J = 2 };
GetSignature(foo.AsIGenerateSignature());
}
void GetSignature(IGenerateSignature sig) {
Console.Write(sig.Generate());
}
public static class GenerateSignatureExtensions
{
public static IGenerateSignature AsIGenerateSignature(this IGenerateSignature me)
{
return me;
}
public static IGenerateSignature AsIGenerateSignature(this Foo me)
{
return new FooSignaturizer(me);
}
public static IGenerateSignature AsIGenerateSignature(this Bar me)
{
return new BarSignaturizer(me);
}
//....
}
Rawling's answer gives a great explanation of the why you are having a problem. As to how to achieve what you want. I might consider something like this:
public interface ISignaturizer
{
IGenerateSignature ToSignaturizer();
}
struct FooSignaturizer : IGenerateSignature, ISignaturizer{
private readonly Foo _foo;
public FooSignaturizer(Foo f) {
_foo = f;
}
public string Generate() {
return _foo.I + ":" + _foo.J;
}
public IGenerateSignature ToSignaturizer()
{
return (IGenerateSignature)this;
}
}
Now BarSignaturizer and QuxSignaturizer can implement the same interface. And then you can do:
GetSignature(((ISignaturizer)fooOrBarOrQux).ToSignaturizer());
Which isn't quite as elegant, but I think should accomplish what you need.

Can I create accessors on structs to automatically convert to/from other datatypes?

is it possible to do something like the following:
struct test
{
this
{
get { /*do something*/ }
set { /*do something*/ }
}
}
so that if somebody tried to do this,
test tt = new test();
string asd = tt; // intercept this and then return something else
Conceptually, what you want to do here is in fact possible within .NET and C#, but you're barking up the wrong tree with regards to syntax. It seems like an implicit conversion operator would be the solution here,
Example:
struct Foo
{
public static implicit operator string(Foo value)
{
// Return string that represents the given instance.
}
public static implicit operator Foo(string value)
{
// Return instance of type Foo for given string value.
}
}
This allows you to assign and return strings (or any other type) to/from objects of your custom type (Foo here).
var foo = new Foo();
foo = "foobar";
var string = foo; // "foobar"
The two implicit conversion operators don't have to be symmetric of course, though it's usually advisable.
Note: There are also explicit conversion operators, but I think you're more after implicit operators.
You can define implicit and explicit conversion operators to and from your custom type.
public static implicit operator string(test value)
{
return "something else";
}
Expanding on MikeP's answer you want something like:
public static implicit operator Test( string value )
{
//custom conversion routine
}
or
public static explicit operator Test( string value )
{
//custom conversion routine
}

Categories