Why usage of dynamic throws exception in runtime? - c#

I have an external dll I'm loading into my appdomain during runtime.
I'm creating an instance of a class from that assembly into a local dynamic variable.
As far as I understood the usage of dynamic in C#, I can simply call a method of it, which will be resolved at run time...
Using this approach, the following code gets me a runtime "'object' does not contain a definition for 'Get'" exception.
I'll try to illustrate the structure as I can't expose the actual code.
External dll name: a.b.c
namespace Ext
{
public static class FactoryCreator
{
public static ProxyFactory CreateFactory()
{
return new ProxyFactory();
}
}
public interface FactoryIfc
{
Proxy Get();
}
internal class ProxyFactory: FactoryIfc
{
private Proxy proxy;
public Proxy Get()
{
if (this.proxy == null)
this.proxy = <a method to create a proxy>
return this.proxy;
}
}
}
I'm using the following code
var assembly = "a.b.c, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<key>,processorArchitecture=MSIL";
var instName = "Ext.FactoryCreator";
dynamic factoryCreator = AppDomain.CurrentDomain.Load(assembly).GetType(instName).GetMethod("CreateFactory").Invoke(null, new object[0]);
dynamic proxy = factoryCreator.Get();
I understand that for FactoryCreator dynamic variable, I need to get the Type and invoke the static method of it, but.. as I said, it is throwing an exception "'object' does not contains a definition for 'Get'" - at the factory.Get() statement - while I would expect dynamic factory to be resolve automatically to the object and service the Get() call.
Observing the situation under a debug session, I can clearly see the Get method using factory.GetType().GetMethods() in the quickwatch window.
Can you explain what is happening?
Must I use factory.GetType().GetMethod("Get") followed by an Invoke? I thought the power of dynamic should work this out automatically in runtime...

Related

Why is RuntimeBinderException thrown when trying to invoke an internal method that has dynamic parameters?

I'm developing an application in C# and in one of my projects I define an interface:
internal interface IArticleResolver
{
string Resolve(string article, dynamic context);
void TestMethod();
}
Within the same project I implement this interface as below:
internal class ArticleResolver : IArticleResolver
{
public string Resolve(string article, dynamic context)
{
throw new NotImplementedException();
}
public void TestMethod()
{
// Pass through.
}
}
This project exposes its internals to a unit test library within the same solution. Within that unit test library, I define the following test:
[Theory]
[MemberData(nameof(Examples))]
internal void Article_Resolver_Should_Resolve_Article_From_Context_As_Expected(
string unresolvedArticle,
dynamic context,
string expectedResolvedArticle)
{
// WHEN we resolve the article using the given context.
this.articleResolver.TestMethod();
string actualResolvedArticle = this.articleResolver.Resolve(unresolvedArticle, context);
// THEN the article should have been resolved as expected.
actualResolvedArticle.ShouldBe(expectedResolvedArticle);
}
What I find is that this.articleResolver.TestMethod() gets invoked without problem, as I expect. However, this.articleResolver.Resolve(...) causes a RuntimeBindingException to be thrown even though it's at the same level of accessibility. The full message is:
'Mofichan.Library.IArticleResolver.Resolve(string, object)' is inaccessible due to its protection level
The only special thing about this method is that it accepts a dynamic parameter, which I'm assuming is the cause. If I make IArticleResolver public, I find that NotImplementedException gets thrown instead (as expected).
Is there a reason why dynamic properties would cause this behaviour and if so, is there a way I can test this code without making the interface or implementing class public?
Edit 1
In case it's useful information, I'm developing this application against .NET Core SDK 1.1 and right now I'm testing it on a Windows 10 machine.
Edit 2
I did some further testing and I'm discovering some interesting results. It seems that RuntimeBinderException is only thrown if you're passing an object with static type dynamic to the method:
// WHEN we resolve the article using the given context.
this.articleResolver.TestMethod();
this.articleResolver.Resolve(unresolvedArticle, "foo"); // NotImplementedException
this.articleResolver.Resolve(unresolvedArticle, new ExpandoObject()); // NotImplementedException
this.articleResolver.Resolve(unresolvedArticle, (dynamic)new ExpandoObject()); // RuntimeBinderException
string actualResolvedArticle = this.articleResolver.Resolve(unresolvedArticle, context);
Edit 3
I no longer get RuntimeBinderException after changing the context parameter of the unit test method to its actual static type (ExpandoObject):
[Theory]
[MemberData(nameof(Examples))]
internal void Article_Resolver_Should_Resolve_Article_From_Context_As_Expected(
string unresolvedArticle,
ExpandoObject context,
string expectedResolvedArticle)
{
// WHEN we resolve the article using the given context.
string actualResolvedArticle = this.articleResolver.Resolve(unresolvedArticle, context);
// THEN the article should have been resolved as expected.
actualResolvedArticle.ShouldBe(expectedResolvedArticle);
}
The method under test itself remains unchanged:
internal class ArticleResolver : IArticleResolver
{
public string Resolve(string article, dynamic context)
{
throw new NotImplementedException();
}
}
While this technically means I no longer have a problem, I'm still very curious about why this happens.

How to get non-static MethodInfo using method name (not in string, not searching in class type)

Consider following code:
public class Test
{
[System.AttributeUsage(System.AttributeTargets.Method)]
class MethodAttribute : System.Attribute
{
public MethodAttribute(System.Reflection.MethodInfo methodInfo)
{
}
}
public void Foo()
{
}
[Method(Test.Foo)] //< THIS IS THE IMPORTANT LINE
public void Boo()
{
}
}
I want to store MethodInfo instance of Foo in attribute of Boo, but problem is, that I cannot use Foo nor Test.Foo to get instance of MethodInfo. I can NOT use typeof(Test).GetMethod("Foo") (not my decision).
Important information:
Generated error is: error CS0120: An object reference is required to access non-static member `Test.Foo()'
I'm coding in Unity3D which is using Mono, not .Net. (more info http://docs.unity3d.com/410/Documentation/ScriptReference/MonoCompatibility.html )
Windows 7
Absolutely unimportant information:
Why I cannot use typeof(Test).GetMethod("Foo"): I'm not allowed. It's not in my power to change this decision. I can not. (Also, personally, I would like to avoid it anyway as it needs to do some lookup instead of getting statically the data. Also it won't be changed automatically during refactoring and will be checking run-time, not compile-time.)
Why I want to do this: later in code, I want to create a delegate of Boo() (this time normally, with an instance) and use in special even system or something. Before it's called, this attribute allows to setup method to be called in prepare for main event (it's optional, it can be null) and I know how to create a delegate when I have an object and a method info.
Why I cannot just provide both delegates when registering or something: because class containing these methods is not always the one who registers to event source, I need to keep the registration code as simple as possible. In other words, I want to avoid situation when person writing method responsible for connecting forgots to add this preparation delegate.
use expression :
static public class Metadata<T>
{
static public PropertyInfo Property<TProperty>(Expression<Func<T, TProperty>> property)
{
var expression = property.Body as MemberExpression;
return expression.Member as PropertyInfo;
}
}
var foo = Metadata<Test>.Property(test => test.Foo);

how to use MarshalByRefObject to call class in different app domain

I am trying to implement a version of example 1 from here http://msdn.microsoft.com/en-us/library/System.MarshalByRefObject(v=vs.110).aspx into my code.
My aim is to have a class with some methods then load that class into a different appdomain and call its method.
so far I have:
public class diffDomain : MarshalByRefObject
{
public int getNumber()
{
return 5;
}
}
internal static class JITCompiler
{
internal static wantNumber()
{
AppDomain domain = AppDomain.CreateDomain("MyDomain");
var newSearch = (diffDomain)domain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
"diffDomain");
}
}
I get an error on the Var newSearch line:
Could not load type 'diffDomain' from assembly 'SVM, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
Your assembly/namespace could be incorrect. To avoid such errors try this:
var newSearch = (diffDomain)domain.CreateInstanceAndUnwrap(
typeof(diffDomain).Assembly.FullName,
typeof(diffDomain).FullName);
What you put in your question isn't your real code, as it has an obvious syntax error.
What you put in your question also doesn't demonstrate the issue you're having, because you excluded relevant information.
What I think you've done is put your classes in a namespace. CreateInstanceAndUnwrap expects a fully qualified name. The example you linked to puts the class in the global namespace, so the unqualified name and qualified names are the same. They probably aren't in what you're trying.

Weird compile-time error on Select() and ToList() LINQ methods

I have a few simple lines of code in a WPF project which give me compilation errors.
var resourceNames = new List<string> { "cmbItem1", "cmbItem2", "cmbItem3", "cmbItem4" };
var comboBoxItems = resourceNames.Select(id => (string)FindResource(id)).ToList();
// other code
The compilation error text is
Error 2 The type
'System.Windows.Forms.Control' is defined in an assembly that is not
referenced. You must add a reference to assembly
'System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089'.
Why have I reference that assembly? I don't use any type from System.Windows.Forms.Control!
If I rewrite the code to make static methods invocations instead of extension methods invocations, it works fine:
var resourceNames = new List<string> { "cmbItem1", "cmbItem2", "cmbItem3", "cmbItem4" };
var comboBoxItems = Enumerable.Select(resourceNames, id => (string)FindResource(id));
comboBoxItems = Enumerable.ToList(comboBoxItems);
// other code
Why is it so? What am I doing wrong?
UPD1:
UPD2: THE ANSWER
I and my colleague have investigated the project and found that the reason of the problem. Here are several facts about our visual studio solution:
The problematic code resides in project called Flyer2. That project has a reference to another project called Global.
The project Global has several classes which provide global accessible extension methods.
One of the extension method has a restriction for a generic type in where clause. The restriction says that the generic type must be an descendant of System.Windows.Control... For some reason existence of a such method produces the compile-time error I've described...
Here is the code of the extension method and the class defining it:
using System.Windows.Forms;
namespace Global
{
public static class ControlExtensions
{
// If I remove the where-clause, the code problem disappears!
public static T FindParentByType<T>(this Control parentControl) where T : Control
{
var currentControl = parentControl != null ? parentControl.Parent : null;
while (currentControl != null)
{
if (currentControl is T)
return (T)currentControl;
currentControl = currentControl.Parent;
}
return null;
}
}
}

Controlling when the Static Constructor is called

In my custom attribute's static constructor, I search the loaded assembly for all classes decorated with my attribute and perform some action on them.
I would like the static constructor to be called as soon as possible during runtime, preferably before execution of the static void Main() entry point.
Currently it only gets called after I make some call to the attribute. I could make such a call elsewhere in my program, but ideally the attribute's functionality would be self-contained.
Looking for answers, I read this on MSDN:
The user has no control on when the static constructor is executed in the program.
But surely there is some tricky, sly, or mischievous workaround to get a static constructor to be called ASAP. Perhaps an attribute, reflection, or some other kind of magic could be used. Can it be done?
Because people would undoubtedly tell me that there is no good reason to do what I ask, I present my purpose and my code: I am trying to use attributes to declaratively configure a db4o factory. If my attribute's static constructor is called after I've already established a connection, then it has no effect and is useless. Therefore it must be called before my program gets a chance to establish such a connection.
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
sealed public class CascadeOnUpdateAttribute : Attribute
{
public bool Flag { get; private set; }
public CascadeOnUpdateAttribute() : this(true) { }
public CascadeOnUpdateAttribute(bool flag)
{
Flag = flag;
}
static CascadeOnUpdateAttribute()
{
var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
from attribute in type.GetCustomAttributes(typeof(CascadeOnUpdateAttribute), false).Cast<CascadeOnUpdateAttribute>()
select new { Type = type, Cascade = attribute.Flag };
foreach (var target in targets)
{
Db4oFactory.Configure().ObjectClass(target.Type).CascadeOnUpdate(target.Cascade);
}
}
}
Update:
I ended up using an abstract attribute with a static method. This way I can derive as many attributes as I like and they will all be applied to a specified config by calling this one method.
public abstract class Db4oAttribute : Attribute
{
public abstract void Configure(IConfiguration config, Type type);
public static void ApplyAttributes(IConfiguration config)
{
var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
from attribute in type.GetCustomAttributes(typeof(Db4oAttribute), false).Cast<Db4oAttribute>()
select new { Type = type, Attribute = attribute };
foreach (var target in targets)
{
target.Attribute.Configure(config, target.Type);
}
}
}
And the call site:
Db4oAttribute.ApplyAttributes(Db4oFactory.Configure());
_db = Db4oFactory.OpenFile("Test.db4o");
As Marc says, I would do it explicitly in Main if I were you.
You can invoke the type initializer for a type explicitly using the Type.TypeInitializer property and invoking it. However, this will cause it to run again even if it's already been run which could produce unexpected results.
I would personally move that code out of the static initializer completely. It's configuration code - why not just make it a static method which you can call explicitly? I'm not even sure I'd have it in the attribute class itself, but at least explicitly calling:
CascadeOnUpdateAttribute.ConfigureDb4oFactories();
is clearer than calling a dummy method or forcing type initialization some other way, just to get a side effect.
If you want the static constructor to get called, then add a dummy method to the type and simply call it at the start of your code (Main etc); if it is a trivial / empty method you might want to mark it for no inlining etc.
class SomeType {
static SomeType() {
Console.WriteLine("SomeType.cctor");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Init() { }
}
static class Program {
static void Main() {
SomeType.Init();
Console.WriteLine("hi");
}
}
You can use reflection to call the static constructor, but I don't recommend it; if you use reflection you can actually call the .cctor multiple times, and that is never a good thing...
You can avoid the static dummy method by calling
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(CascadeOnUpdateAttribute).TypeHandle)
I think the use of the static constructor smells; I would consider refactoring your code to control access to the db4o factory so that you don't need to use it.

Categories

Resources