Code Puzzler: How quickly can you figure out why this acting "weird"?
-
Roughly 90 seconds, mostly working out which
Console.WriteLine
call was which. :) Spoilers ahead - select the block to view:Take a copy of the static field; Create a new instance, thus overwriting the static field; Compare the new instance to the copy of the old value of the static field - result = false; Compare the new instance to the current value of the static field - result = true;
Damnit Chris, we need a
<div class="spoiler">
!
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Richard Deeming wrote:
select the block to view:
Now THAT is snazzy!
Latest Article - Building a Prototype Web-Based Diagramming Tool with SVG and Javascript Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny Artificial intelligence is the only remedy for natural stupidity. - CDP1802
-
Well, it will "work", in the sense that it won't overwrite the static instance. But it won't work, in the sense that the returned instance will be using the default connection string for the context, not the connection string from the instance passed in. :)
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Richard Deeming wrote:
But it won't work, in the sense that the returned instance will be using the default connection string for the context, not the connection string from the instance passed in.
Hmm. But the parameterless constructor uses the connection string of the (hopefully) already initialized context:
public ModelDataContext() : base(Context.Connection)
However, it's a moot point anyways as I refactored the whole mess into something much less weird. It'll be an interesting question though to pose to a couple of the devs at work, though I'll reduce the complexity of it omitting the DataContext base class - it's rather superfluous to the example.Latest Article - Building a Prototype Web-Based Diagramming Tool with SVG and Javascript Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny Artificial intelligence is the only remedy for natural stupidity. - CDP1802
-
Richard Deeming wrote:
But it won't work, in the sense that the returned instance will be using the default connection string for the context, not the connection string from the instance passed in.
Hmm. But the parameterless constructor uses the connection string of the (hopefully) already initialized context:
public ModelDataContext() : base(Context.Connection)
However, it's a moot point anyways as I refactored the whole mess into something much less weird. It'll be an interesting question though to pose to a couple of the devs at work, though I'll reduce the complexity of it omitting the DataContext base class - it's rather superfluous to the example.Latest Article - Building a Prototype Web-Based Diagramming Tool with SVG and Javascript Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny Artificial intelligence is the only remedy for natural stupidity. - CDP1802
OK, so it's not quite as bad as I though. :) You could still break it though:
var context1 = new ModelDataContext(new SqlConnection("server=A;database=B"));
var context2 = new ModelDataContext(new SqlConnection("server=C;database=D"));CreateNewContext(context1, out var newConn, out var newContext);
// As expected:
Console.WriteLine(newConn.ConnectionString == context1.Connection.ConnectionString); // True// Not as expected:
Console.WriteLine(newContext.Connection.ConnectionString == context1.Connection.ConnectionString); // False
Console.WriteLine(newContext.Connection.ConnectionString == newConn.ConnectionString); // False
Console.WriteLine(newContext.Connection == newConn); // False// Also not as expected:
Console.WriteLine(newContext.Connection.ConnectionString == context2.Connection.ConnectionString); // True
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
You probably could, with a bit of thinking about it - it's obvious when you see it, but it's a stinker to spot if you didn't write the code (and probably even harder if you did if you are anything like me: I tend to see what I meant to write, rather than what I did :-O )
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay... AntiTwitter: @DalekDave is now a follower!
I also see what I meant to write as opposed to what I actually wrote. I've been tired and looked at two spellings of same word and get compiler errors and don't spot the error for some time.
Everyone has a photographic memory; some just don't have film. Steven Wright
-
I also see what I meant to write as opposed to what I actually wrote. I've been tired and looked at two spellings of same word and get compiler errors and don't spot the error for some time.
Everyone has a photographic memory; some just don't have film. Steven Wright
Annoying, isn't it? :-D
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay... AntiTwitter: @DalekDave is now a follower!
-
Annoying, isn't it? :-D
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay... AntiTwitter: @DalekDave is now a follower!
Yes very frustrating. As I get older it seems to be more prevalent.
Everyone has a photographic memory; some just don't have film. Steven Wright
-
OK, so it's not quite as bad as I though. :) You could still break it though:
var context1 = new ModelDataContext(new SqlConnection("server=A;database=B"));
var context2 = new ModelDataContext(new SqlConnection("server=C;database=D"));CreateNewContext(context1, out var newConn, out var newContext);
// As expected:
Console.WriteLine(newConn.ConnectionString == context1.Connection.ConnectionString); // True// Not as expected:
Console.WriteLine(newContext.Connection.ConnectionString == context1.Connection.ConnectionString); // False
Console.WriteLine(newContext.Connection.ConnectionString == newConn.ConnectionString); // False
Console.WriteLine(newContext.Connection == newConn); // False// Also not as expected:
Console.WriteLine(newContext.Connection.ConnectionString == context2.Connection.ConnectionString); // True
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Richard Deeming wrote:
You could still break it though:
Yeah, but it's never used that way - two different connection strings. But ideally, it shouldn't be possible to use it that way. Sigh. The irony of this is that it's code I wrote a while back that my DataContext extension methods rely on, and looking at this now, it's some serious code smell. Fortunately, fixing it affects only a couple web servers that are in operation, but I feel embarrassed. But I blame .NET's DataContext. :laugh: It does way to much with regards to the state of the Table object. I get what they're trying to do, but there must be a better way that doesn't end up throwing exceptions like "this object was created in a different data context."
Latest Article - Building a Prototype Web-Based Diagramming Tool with SVG and Javascript Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny Artificial intelligence is the only remedy for natural stupidity. - CDP1802
-
And no, this isn't a programming question in the lounge. I started asking this question in the QA forum because it had me totally stumped. As I was filling out the "What I've tried" I had a major :doh: :doh: :doh: :doh: moment. To prove I'm not asking for help on the lounge, I posted a solution on [my blog](https://marcclifton.wordpress.com/2018/05/31/the-fix/). You'll need to use the password "fizbin" as the blog post is specifically for this lounge post and eventually I'll delete the post. It is a fun one though. Here's the code:
public class ModelDataContext : DataContext { public static ModelDataContext Context; public ModelDataContext(DbConnection conn) : base(conn) { Context = this; } } class Program { static ModelDataContext mdc = new ModelDataContext(new SqlConnection("\[some string\]")); static void CreateNewContext(DataContext context, out SqlConnection conn, out DataContext newContext) { conn = new SqlConnection(context.Connection.ConnectionString); newContext = (DataContext)Activator.CreateInstance(context.GetType(), new object\[\] { conn }); Console.WriteLine(context == newContext); } static void Main(string\[\] args) { SqlConnection conn2; DataContext newdc; CreateNewContext(ModelDataContext.Context, out conn2, out newdc); Console.WriteLine(ModelDataContext.Context == newdc); } }
and the result is: False True Why is the second equality True when the first is False??? And for the bonus prize, what's a fix?
Latest Article - Building a Prototype Web-Based Diagramming Tool with SVG and Javascript Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny Artificial intelligence is the only remedy for natural stupidity. - CDP1802
The reason for the results are pretty obvious, when a new instance is created in "CreateNewContext", the parameter "context" is still referring to the original context, not the new one ==> false; When the main program does the compare afterwards, the comparison is done to the static that holds the new context ==> true. Fixing this is not obvious because you didn't specify what the correct behavior should be. Do you wish it to be "True" always, or "False" always :) Simply update the context parameter in the method to get True always, but I would personally recommend to re-write this whole thing, it is full of code smells. Perhaps some practice in TDD would also be helpful. Cheers, Anthony
-
And no, this isn't a programming question in the lounge. I started asking this question in the QA forum because it had me totally stumped. As I was filling out the "What I've tried" I had a major :doh: :doh: :doh: :doh: moment. To prove I'm not asking for help on the lounge, I posted a solution on [my blog](https://marcclifton.wordpress.com/2018/05/31/the-fix/). You'll need to use the password "fizbin" as the blog post is specifically for this lounge post and eventually I'll delete the post. It is a fun one though. Here's the code:
public class ModelDataContext : DataContext { public static ModelDataContext Context; public ModelDataContext(DbConnection conn) : base(conn) { Context = this; } } class Program { static ModelDataContext mdc = new ModelDataContext(new SqlConnection("\[some string\]")); static void CreateNewContext(DataContext context, out SqlConnection conn, out DataContext newContext) { conn = new SqlConnection(context.Connection.ConnectionString); newContext = (DataContext)Activator.CreateInstance(context.GetType(), new object\[\] { conn }); Console.WriteLine(context == newContext); } static void Main(string\[\] args) { SqlConnection conn2; DataContext newdc; CreateNewContext(ModelDataContext.Context, out conn2, out newdc); Console.WriteLine(ModelDataContext.Context == newdc); } }
and the result is: False True Why is the second equality True when the first is False??? And for the bonus prize, what's a fix?
Latest Article - Building a Prototype Web-Based Diagramming Tool with SVG and Javascript Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny Artificial intelligence is the only remedy for natural stupidity. - CDP1802
It took about a minute to solve. Assigning over the static for each constructor call is a WTF (as others have called out). Way too many statics in this Program, if it was rewritten to eliminate all of the statics, then the Program instance would hold a single context and the Main would look like this:
Main(...)
{
new Program().Run();
}If new instances of the "context" are really needed, then create a Copy constructor to reuse the default context settings on a new instance. Or use your favorite IOC container.
-
You probably could, with a bit of thinking about it - it's obvious when you see it, but it's a stinker to spot if you didn't write the code (and probably even harder if you did if you are anything like me: I tend to see what I meant to write, rather than what I did :-O )
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay... AntiTwitter: @DalekDave is now a follower!
OriginalGriff wrote:
I tend to see what I meant to write, rather than what I did
Yup that's me! As an answer: I haven't gone further in the thread, but at first glance the FALSE comes from comparing 2 different instances, where the TRUE result is comparing the same instance to itself? Fix: the first comparison is not necessary
-
And no, this isn't a programming question in the lounge. I started asking this question in the QA forum because it had me totally stumped. As I was filling out the "What I've tried" I had a major :doh: :doh: :doh: :doh: moment. To prove I'm not asking for help on the lounge, I posted a solution on [my blog](https://marcclifton.wordpress.com/2018/05/31/the-fix/). You'll need to use the password "fizbin" as the blog post is specifically for this lounge post and eventually I'll delete the post. It is a fun one though. Here's the code:
public class ModelDataContext : DataContext { public static ModelDataContext Context; public ModelDataContext(DbConnection conn) : base(conn) { Context = this; } } class Program { static ModelDataContext mdc = new ModelDataContext(new SqlConnection("\[some string\]")); static void CreateNewContext(DataContext context, out SqlConnection conn, out DataContext newContext) { conn = new SqlConnection(context.Connection.ConnectionString); newContext = (DataContext)Activator.CreateInstance(context.GetType(), new object\[\] { conn }); Console.WriteLine(context == newContext); } static void Main(string\[\] args) { SqlConnection conn2; DataContext newdc; CreateNewContext(ModelDataContext.Context, out conn2, out newdc); Console.WriteLine(ModelDataContext.Context == newdc); } }
and the result is: False True Why is the second equality True when the first is False??? And for the bonus prize, what's a fix?
Latest Article - Building a Prototype Web-Based Diagramming Tool with SVG and Javascript Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny Artificial intelligence is the only remedy for natural stupidity. - CDP1802
It's the assignment of the static member from the instance constructor. HUGE no-no. If you want to make a singleton without using a DI framework, at least make the constructor private and have the static "Context" member be a property that will create a new object if one doesn't exist, and set it to a backing field. Something like this (might need to make Current a method instead of property if you need to pass constructor arguments, but you get the idea):
public class Singleton
{
private Singleton _current;public Singleton Current { get { if (\_current == null) { \_current = new Singleton(); } return \_current; } } private Singleton() { }
}
-
And no, this isn't a programming question in the lounge. I started asking this question in the QA forum because it had me totally stumped. As I was filling out the "What I've tried" I had a major :doh: :doh: :doh: :doh: moment. To prove I'm not asking for help on the lounge, I posted a solution on [my blog](https://marcclifton.wordpress.com/2018/05/31/the-fix/). You'll need to use the password "fizbin" as the blog post is specifically for this lounge post and eventually I'll delete the post. It is a fun one though. Here's the code:
public class ModelDataContext : DataContext { public static ModelDataContext Context; public ModelDataContext(DbConnection conn) : base(conn) { Context = this; } } class Program { static ModelDataContext mdc = new ModelDataContext(new SqlConnection("\[some string\]")); static void CreateNewContext(DataContext context, out SqlConnection conn, out DataContext newContext) { conn = new SqlConnection(context.Connection.ConnectionString); newContext = (DataContext)Activator.CreateInstance(context.GetType(), new object\[\] { conn }); Console.WriteLine(context == newContext); } static void Main(string\[\] args) { SqlConnection conn2; DataContext newdc; CreateNewContext(ModelDataContext.Context, out conn2, out newdc); Console.WriteLine(ModelDataContext.Context == newdc); } }
and the result is: False True Why is the second equality True when the first is False??? And for the bonus prize, what's a fix?
Latest Article - Building a Prototype Web-Based Diagramming Tool with SVG and Javascript Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny Artificial intelligence is the only remedy for natural stupidity. - CDP1802
The first 'true' you receive you explicitly cast the object on the function call to a DataContext type. The second you're comparing a ModelDataContext.Context object - which I'm not sure if it's a DataContext type - if not - then you're comparing unlike objects and the call will fail. Try explicitly casting the ModelDataContext.Context, and for overkill the newdc to a DataContext type and do the comparison that way. ie: Console.WriteLine((DataContext) ModelDataContext.Context == (DataContext) newdc);
-
And no, this isn't a programming question in the lounge. I started asking this question in the QA forum because it had me totally stumped. As I was filling out the "What I've tried" I had a major :doh: :doh: :doh: :doh: moment. To prove I'm not asking for help on the lounge, I posted a solution on [my blog](https://marcclifton.wordpress.com/2018/05/31/the-fix/). You'll need to use the password "fizbin" as the blog post is specifically for this lounge post and eventually I'll delete the post. It is a fun one though. Here's the code:
public class ModelDataContext : DataContext { public static ModelDataContext Context; public ModelDataContext(DbConnection conn) : base(conn) { Context = this; } } class Program { static ModelDataContext mdc = new ModelDataContext(new SqlConnection("\[some string\]")); static void CreateNewContext(DataContext context, out SqlConnection conn, out DataContext newContext) { conn = new SqlConnection(context.Connection.ConnectionString); newContext = (DataContext)Activator.CreateInstance(context.GetType(), new object\[\] { conn }); Console.WriteLine(context == newContext); } static void Main(string\[\] args) { SqlConnection conn2; DataContext newdc; CreateNewContext(ModelDataContext.Context, out conn2, out newdc); Console.WriteLine(ModelDataContext.Context == newdc); } }
and the result is: False True Why is the second equality True when the first is False??? And for the bonus prize, what's a fix?
Latest Article - Building a Prototype Web-Based Diagramming Tool with SVG and Javascript Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny Artificial intelligence is the only remedy for natural stupidity. - CDP1802
It is a simple newb mistake. Basically, you have written overly complex code making it hard for you to debug. Simplify the syntax as much as possible and the symantec issues will reveal themselves ;)