This is a very specific problem. Not quite sure how to even word it. Basically I am implementing the unit of work and repository pattern, I have a dynamic object that I convert to an int, but if I use var
it will throw an exception when trying to call the method.
I tried to remove all the trivial variables to this problem that I can. For some reason I only see it happen with these two design patterns. The exception I get is Additional information: 'BlackMagic.ITacoRepo' does not contain a definition for 'DoStuff'
Here is the code:
class BlackMagic
{
static void Main(string[] args)
{
dynamic obj = new ExpandoObject();
obj.I = 69;
UnitOfWork uow = new UnitOfWork();
int i1 = Convert.ToInt32(obj.I);
var i2 = Convert.ToInt32(obj.I);
if(i1.Equals(i2))
{
uow.TacoRepo.DoStuff(i1); // Works fine
uow.TacoRepo.DoStuff(i2); // Throws Exception
}
}
}
class UnitOfWork
{
public ITacoRepo TacoRepo { get; set; }
public UnitOfWork()
{
TacoRepo = new TacoRepo();
}
}
class Repo<T> : IRepo<T> where T : class
{
public void DoStuff(int i)
{
}
}
interface IRepo<T> where T : class
{
void DoStuff(int i);
}
class TacoRepo : Repo<Taco>, ITacoRepo
{
}
interface ITacoRepo : IRepo<Taco>
{
}
class Taco
{
}
EDIT: The main question I am trying to find an answer for, is why would the exception get thrown by calling DoStuff
inside the unit of work (while using the repo) but not get thrown if DoStuff existed in the BlackMagic
class.
DoStuff
is called and see what actual runtime typei2
is? – Philanderi2
isSystem.Int32
. But I think it's behaving as ifi2
is a dynamic reference to something else: If you pass adynamic
argument to a method, overload resolution is done at runtime.uow.TacoRepo.DoStuff((int)i2);
works fine . – Philanderi2
. However, sincei2
came from aExpandoObject
it's declaring and reflected type are null, and as a result it does not match theint
requirement ofDoStuff
. Strange indeed, perhaps you should just avoid using dynamic here in that fashion. – Titaniumdynamic obj = JObject.Parse(strJson)
so is it still the same reason for not working? – Headmastervar
there. As for your question with regards to parsing a json string into a dynamic object, I think that requires the same type of reflection as a model binder, and with dynamic that option doesn't seem to exist. Unsure though off the top of my head what the connection between this example shown and your issue with parse is wrt dynamic. – Titaniumvar i2 = Int32.Parse(obj.I.ToString())
throws the same exception.var i2 = Int32.Parse($"{obj.I}");
doesn't. @TravisJ the declaring and reflected types ofi1
are null as well here. – PhilanderGetType()
is runtime. By the compiler's logic,var i2
means you're happy fori2
to be dynamic. What's weirding me is that according to my understanding ofdynamic
and overload resolution, it ought to be happy withDoStuff(int)
-- so clearly my "understanding" isn't. – Philandervar i2
assigned theConvert.ToInt32()
method, wouldn't that tell the compiler thati2
will be anint
? – Headmastervar i2 = (int)Convert.ToInt32(obj.I);
makes i2 non-dynamic. In fact,var i2 = (int)obj.I;
makes i2 non-dynamic. Maybe more gobsmacked than dumbfounded, if you want to be pedantic. – PhilanderUnitOfWork
a methodpublic void Foo(int x) { }
, I can calluow.Foo(i2)
with dynamici2
. I don't understand how that method differs fromITacoRepo.DoStuff(int)
. – Philandervar i2 = Convert.ToInt32((object)obj.I);
no more exception. I guess I don't fully understand why the parameters you pass in have any effect on what is returned. I meanConvert.ToInt32
always returns anint
so I don't understand why it is dynamic instead – HeadmasterConvert.ToInt32()
, and saying "OK, this is a dynamic parameter. And we're assigning the Int32 value this call returns to something declaredvar
, so but a dynamic came in, so we'll go and make thatvar
dynamic
too." It's changing the meaning of thatvar
declaration. The return value fromConvert.ToInt32()
isn't changing -- the compiler is changing what happens to it after return. Dump the MSIL and see what you get. – Philanderint
is not being used as the type is because the rule for using implicit conversion on the return type of the method call (in this case ToInt) has several conditions, one of which is violated in this situation, notably that "The primary-expression has compile-time type dynamic." As a result the implicit conversion is not used, and the best accessible type (object) is used as a result. There is no definition for DoStuff(object) and as a result the runtime exception occurs. – TitaniumDoStuff
out of the Repo and put it in the main `BlackMagic' class then pass i2 in – Headmaster