Passing Dynamic Object to C# Method Changes Return Type

Passing dynamic object to C# method changes return type

This is because almost any operation involving a dynamic value is resolved dynamically at execution time. There are no exceptions made for cases where actually there's only one method present at compile-time; the language is simpler that way. (For certain calls, the compiler does perform enough resolution at compile-time to ensure that there is at least one method with a suitable number of parameters - this is specified in the C# 5 spec in section 7.5.4, but that doesn't affect the effective return type.)

From the C# 5 spec, section 7.6.5:

An invocation-expression is dynamically bound if at least one of the following holds:

  • The primary-expression has compile-time type dynamic.
  • At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.

In this case the compiler classifies the invocation-expression as a value of type dynamic. [...]

There are a few operations involving dynamic values which still have a non-dynamic overall type. For example:

  • d is Foo is always bool
  • d as Foo is always Foo
  • new Foo(d) is always Foo even though the exact constructor to use is determined at execution time

But any method call is treated as having a return type of dynamic.

Dynamic method return type in C#

As far as I understand the problem, you need to return a more complete data when the retriever is the admin, and a not-so-complete one when not.

If that is the objective, then you can retrieve the appropriate data from the database and fill in an object of one of the following classes:

public class PersonData {
public string Name { get; private set; }
public string Surname { get; private set; }
}

public class ExtendedPersonData: PersonData {
public string Name { get; private set; }
public string Surname { get; private set; }
public string Address { get; private set; }
}

Since the latter class inherits from the former, you can just create a List<PersonData> and that will cover both cases.

Another, different approach: the data class takes into account the user in order to return or not certain data:

class Person {
public Person(User usr, string address)
{
this.User = usr;
this.address = address;
}

public string User { get; private set; }
public string Name { get; private set; }
public string Surname { get; private set; }
public string Address {
get {
string toret = "N/A";

if ( this.User.IsAdmin() ) {
toret = this.address;
}

return toret;
}
}

private string address;
}

Neither of both solutions is perfect, and both have their own issues, but the problem, at least how you stated it, cannot be solved.

Hope this helps.

Generic method return dynamic for unknown reason

Almost everything you do with a value of type dynamic results in a value of dynamic. Sure, you know the return type of the TryConvertToEnum method you intend to call - but you're passing in a dynamic argument, which means it's not bound until execution time. At execution time, there could be a whole other method with a string parameter and a different return type.

There are a very few cases of expressions which include dynamic values but still don't have a result type of dynamic. Off the top of my head, they are:

  • Constructor calls (always the type being constructed)
  • The is operator (always bool)
  • The as operator (always the type named as the second operand)

In your case, just use object instead of dynamic and the call will be statically bound instead, and value will be of type MyEnum?.

How to return dynamic return types in methods? C#

You're solving the wrong problem. If you have a superclass A, with subclasses B, C, etc., that all have similar functionality, you want to do the following:

  1. Make A an interface that B, C, etc. implement. Code that works with B or C instances does by working through the interface provided by A. If you can define a common set of operations that work on all the types, then this is all you need to do.

  2. If you can't define a common set of operations, e.g. you have code similar to:

    A foo = GetA();
    if(foo is B) {
    B bFoo = (B) foo;
    // Do something with foo as a B
    } else if(foo is C) {
    C cFoo = (C) foo;
    // Do something with foo as a C
    } ...

    Or even this (which is basically the same thing, just using extra information to emulate what the type system already provides for you):

    A foo = GetA();
    MyEnum enumeratedValue = foo.GetEnumeratedValue();
    switch(enumeratedValue) {
    case MyEnum.B:
    B bFoo = (B) foo;
    // Do something with foo as a B
    break;
    case MyEnum.C:
    C cFoo = (C) foo;
    // Do something with foo as a C
    break;
    }

    Then what you really want is to do something like:

    A foo = GetA();
    foo.DoSomething();

    Where each subclass would implement the corresponding branch of the switch statement. This is actually better in several ways:

    • It uses less overall code.
    • Since the implementations of the cases live in the various implementation classes, no casting is necessary; they can access all the member variables directly.
    • Since you're not building a big switch/case block separate from the actual B and C implementations, you don't run any risk of accidentally forgetting to add a corresponding case if add a new subclass. If you leave the DoSomething() method out of a subclass of A, you will get a compile-time error.

Edit: In response to your comment:

If your DoSomething() routine needs to operate on a Form or other GUI element, just pass that element into the method. For example:

public class B : A {
public void DoSomething(MyForm form) {
form.MyLabel.Text = "I'm a B object!";
}
}

public class C : A {
public void DoSomething(MyForm form) {
form.MyLabel.Text = "I'm a C object!";
}
}

// elsewhere, in a method of MyForm:

A foo = GetA();
foo.DoSomething(this);

Alternatively, an even better idea might be to turn your B and C classes into custom controls, since they seem to encapsulate display logic.

Dynamically create or set the return type of a function in the function

The only possible way for the consumer of such a method to actually rely on the fact that the return type is dynamic is if, at least for that one method call, the return type is statically known at compile time.

There is a specific feature for a method that has some type unknown at the time the method is written, but fixed when a particular call to that method is make. That feature is called "generics".

public T Foo<T>()
where T : new()
{
return new T();
}

That's really the only available option for a truly dynamic return type that has much potential for really being useful.

If that's not what you want, or that is not a workable option for you, then odds are pretty high your method shouldn't have a dynamically changing return type. Instead it should have a fixed return type of some more generalized type that can have multiple implementations. Generally this would mean an interface, to which you can return one of any number of possible implementations. This should be done if the caller doesn't need to really know or care what the implementation is, but rather all they need to know is that they are given some implementation of an interface that exposes all of what they need. In your case, perhaps something like Control would be workable, if the caller only need to know that they are given some type of control, and to which the API of Control provides everything that they need to do with it.

Method declared with dynamic input parameter and object as return type in fact returns dynamic

The problem is that you're calling a method with a dynamic argument. That means it's bound dynamically, and the return type is deemed to be dynamic. All you need to do is not do that:

object dObj = "123";
var obj = Convert(dObj);

Then the Convert call will be statically bound, and obj will have a type of object.

From the C# 5 specification, section 7.6.5:

An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:

  • The primary-expression has compile-time type dynamic.
  • At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.

In this case the compiler classifies the invocation-expression as a value of type dynamic.

Dynamic arguments and return type

You cannot call extension methods on object of type dynamic. Extension methods are a purely compile time construct. At runtime, it will search for an instance method called FirstOrDefault, not find one, and therefore error out.

Your solutions are to either cast the result of Query to the appropriate type before calling FirstOrDefault on it, or to not use the extension method syntax and instead write out: Queryable.FirstOrDefault(Query<T>(...)) which will tell the runtime binder that it's trying to bind the result of Query to the appropriate static method, rather than an instance method.

As for why any method accepting arguments of type dynamic always resolves to an expression of type dynamic: that's simply what the specs say to do. The whole point of using dynamic is to defer binding of the methods until runtime, so it cannot be sure of what the value of that expression will be until runtime; to get around that, it needs to propagate the dynamic type.

Why does a method that returns a type result in an implicit typing of dynamic?

Why does a method that returns a type result in an implicit typing of dynamic?

Because that's the best the compiler can do, given the information it has.

The reason methodResult is dynamic is that the entire expression used to initialize it is dynamic. And that's the case, because data is dynamic.

When you use dynamic, you're telling the compiler to not resolve types at compiler time. Instead, they should be resolved according to the normal compiler rules, but at run-time.

The fluentClass variable could hold some implementation of FluentClass that contains an overload that matches the run-time type of the argument data. In that case, a different implementation of SomeMethod() could be called, returning a different type.

You've told the compiler to defer type resolution to run-time, so it can't force things back into a strongly-typed context unless you tell it explicitly what type things are. In your example, it can't, so the type remains dynamic.

Note that you might have thought that the compiler would identify the one overload you've provided, based on its parameter type of dynamic. But that's not how dynamic works. The dynamic parameter affects only the implementation of the method, i.e. the code in its body. As far as calling the method goes, the parameter is essentially object. It's just that when the parameter value is used in the method body, it has the features of dynamic.

Another way to think of dynamic is that it accepts any object as input (like object), but then allows you to use any member of that object that you believe exists (if it doesn't exist an exception will be thrown at run-time). Using dynamic defers the compiler logic downstream, i.e. for the output of any usages of the dynamic variable, but doesn't affect the input, i.e. the assignment of that variable.

Note also that even if the method call is completely unambiguous, e.g. a static method where there's only one method with that name, you'll still get a dynamic result. Once you start using dynamic, it sticks with you until you provide an explicit cast to get back to a known type.



Related reading:

Very similar to your question, if not actually duplicates:

Why does a method invocation expression have type dynamic even when there is only one possible return type?

Why does this method keep returning dynamic despite the return type in the signature?

Why doesn't this string.Format() return string, but dynamic?

More general discussion of dynamic:

What is the 'dynamic' type in C# 4.0 used for?

C# 4: Real-World Example of Dynamic Types

Passing an instance of a dynamic type to a generic method in a generic class

To answer your question:

var type = typeof(abc);
object instanceToModify = new abc();

var typeToCreate = typeof(GenericClass<>).MakeGenericType(type);
var methodToCall = typeToCreate.GetMethod("GenericMethod");

var genericClassInstance = Activator.CreateInstance(typeToCreate);
methodToCall.Invoke(genericClassInstance, new[] { instanceToModify });

DEMO

But:

If your type is only known at runtime your instance must be handled in a variable declared as object or dynamic. In that case you can change your method signature to:

public object GenericMethod(object obj)
{
// modify the object in some (arbitrary) way
IEnumerable<FieldInfo> fields = obj.GetType().GetRuntimeFields();
foreach (var field in fields)
{
if (field.FieldType == typeof(string))
{
field.SetValue(obj, "This field's string value was modified");
}
}

return obj;
}

There's no need for a generic class/method.



Related Topics



Leave a reply



Submit