|
In the following snippet of a class, I'm passing a reference to connection_string (a private field in the same class) into ExecuteScalar method by way of the connection_string parameter.
But in SomeMethod , I'm using connection_string , even though I haven't passed it into the method as a parameter.
Which way is the most common and why?
class public DBCall
{
private string connection_string = "...";
private void SomeMethod()
{
var zipcode = ExecuteScalar<string>("select zipcode from ZIpcodes where Zip='92108'", connection_string);
}
public T ExecuteScalar<T>(string queryString, string connection_string)
{
using (OleDbConnection conn = new OleDbConnection (connection_string))
{
using (OleDbCommand cmd = new OleDbCommand (queryString , conn))
{
var result = cmd.ExecuteScalar ( );
if (Convert.IsDBNull (result) && typeof (T).IsValueType)
return default (T);
else
return (T) (result);
}
}
}
private void treeView1_NodeMouseClick(object sender , TreeNodeMouseClickEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
string loadrowset = e.Node.Text;
Rowset rowset = (Rowset) Enum.Parse (typeof (Rowset) , loadrowset);
using (OleDbConnection conn = new OleDbConnection (ConnectionString))
{
OleDbSchemaTable s = new OleDbSchemaTable (rowset , conn);
DataTable dt = new DataTable ( );
dt = s.datatable;
dataGridView1.Enabled = true;
dataGridView1.DataSource = dt;
}
}
else
{
return;
}
}
The lack of surety in programming is part of the reason software is fragile.
|
|
|
|
|
Yes it is fine, since the private string is part of the class definition, and therefore is present in every instance of the DBCall class. However, I would suggest you use a different name in the parameter field to make it clear which object you are referring to in the following code. I am assuming that ExecuteScalar could also be called from elsewhere with a different value for that parameter.
|
|
|
|
|
Than you, Richard. Good point about using a different name. I meant to go back and edit that. Someone told me that they would be "pissed" if a variable was used in a method, that wasn't passed into it. He said it makes the code hard to read and not portable. He has a point, but I did it both ways in the program in question and the one where I didn't pass fields into methods looked cleaner. It might be because I use long variable names, which people laugh at me for, but people rarely have to ask what I meant. I drigress...
The lack of surety in programming is part of the reason software is fragile.
|
|
|
|
|
Rick_Bishop wrote: they would be "pissed" if a variable was used in a method, that wasn't passed into it. The fact that both connection_string and SomeMethod are both private, and also close together in the code means that it is not unreasonable to do it that way. Just as long as it does not create a maintenance problem in the future.
Rick_Bishop wrote: because I use long variable names Something that I think far too few people do. Reading your code it is pretty obvious what the name connection_string refers to. As opposed to something like textBox8.Text which means absolutely nothing.
|
|
|
|
|
Rick_Bishop wrote: public T ExecuteScalar<T>(string queryString, string connection_string)
That method is going to force you to write code which is vulnerable to SQL Injection[^]. You have to be able to pass parameters to the query as parameters, not using string concatenation.
private OleDbCommand CreateCommand(OleDbConnection connection, string queryString, object[] parameters)
{
var command = new OleDbCommand("", connection);
if (parameters != null && parameters.Length != 0)
{
queryString = Regex.Replace(queryString, @"\{(\d+)\}", match =>
{
int index = int.Parse(match.Groups[1].Value);
object value = parameters[index];
string name = "@p" + command.Parameters.Count;
command.Parameters.AddWithValue(name, value);
return "?";
});
}
command.CommandText = queryString;
return command;
}
public T ExecuteScalar<T>(string queryString, params object[] parameters)
{
using (OleDbConnection connection = new OleDbConnection(connection_string))
using (OleDbCommand command = CreateCommand(connection, queryString, parameters))
{
var result = cmd.ExecuteScalar();
if (Convert.IsDBNull(result)) return default(T);
return (T)result;
}
}
private void SomeMethod(string zipCode)
{
var zipcode = ExecuteScalar<string>("select zipcode from Zipcodes where Zip = {0}", zipCode);
...
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Just getting back to this. Thank you for your comments. The querystring is being built by another method and isn't SQL Injection isn't going to be a problem. I can't use parameters as defined by the db provider because this same method is used for oledb and odbc and sqlclient connections.
The lack of surety in programming is part of the reason software is fragile.
|
|
|
|
|
There are many things "not so clean" in your code.
Why does that class have a field for the connection string, but otherwise require the connection string to be passed into a public function? Why should a consumer of this class know anything about connection strings?
Also, fields and parameters should "look" differently to avoid confusion of the human reader (I think it is a BUG in Microsoft's specification of scope ).
Then there's some UI code also: treeView1_NodeMouseClick . And there is another kind of connection string - now ConnectionString , previously connection_string . Totally confusing.
Also, the else {return;} is not useful.
Obviously, that class is responsible for more than one thing. Hence it needs refactoring to single responsibilities. I am sure that those confusing connection string will be resolved during that refactoring.
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
Thanks, Bernard. I'm just getting back to this. ConnectionString was typo and thank you for the tip about else {return;}.. not sure why that's there actually. This program actually connects to many different types of databases and with many different providers, so the connection string had a different scope than is typical, I think. I like the way you worded that.
The lack of surety in programming is part of the reason software is fragile.
|
|
|
|
|
If you have the info in a field, then don't pass it as a parameter
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Thank you, this is why I asked. My coworker does not agree, but it sounds like he is in the minority.
The lack of surety in programming is part of the reason software is fragile.
|
|
|
|
|
Once they exist as a member, any parameter would be redundant. It's a nice way of sharing variables inside the black box of code. It is not used for things that come from the outside and are only used inside that method - those remain parameters.
We group variables and code that belong together in an object because it is superiour to the procedural model where you pass everything as a parameter.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
If I recall correctly the method will use the parameter value of the variable.
If you would like to use the class variable you need to use "this" in front.
See here [^] to see the result.
using System;
public class Program
{
public static void Main()
{
Test t = new Test();
t.WriteValue("abc");
}
}
public class Test{
private string teststring = "xyz";
public void WriteValue(string teststring){
Console.WriteLine(teststring);
Console.WriteLine(this.teststring);
}
}
Hope this helps
|
|
|
|
|
Finally picking this back up. I appreciate your feedback. My coworker and I were arguing this point and the consensus is that if a variable is available in a field, use it and don't pass it into methods as a parameter. Thank you!
The lack of surety in programming is part of the reason software is fragile.
|
|
|
|
|
I agree, with perhaps the exception of the constructor.
|
|
|
|
|
A recent comment by OriginalGriff [^] reminded me of the fact that this:
private (string, int, string) getstuff()
{
return (S1: "boo", I1: 99, S2: "ddd");
} when called: the result will not expose the field Names you specified in the ValueTuple declaration: any attempt to use those Names will not compile. But, this:
private (String S1, int I1, string S2) getstuff()
{
return ("boo", 99, "ddd");
} when called,: compiles, and the result exposes the Names. Of course, you can specify Names at any time:
String xS1, int xI1, string xS2) stuff1 = GetStuff(); independently of whatever "format" the source ValueTuple is in.
This leads me to the hypothesis that internal specification of ValueTuple field Names is probably redundant if said ValueTuple is returned from the Class. Of course, that is not to say that defining the Names internally is not useful ... if those Names are used internally.
It also suggests, to me, that if a ValueTuple is being passed around, every consumer must declare those Names to keep them "fresh" (of course, use of 'dynamic is ignored here).
But, where does this lead you ?
Would you consider using a Property like :
public (string S1, int I1, string S2) VTProp {set; get;} To make sure the field Names stayed "fresh" even when it has its value set without field Names: VTProp = ("hello", 23, "exit"); ?
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
|
|
|
|
|
Joseph Woodward has a blog post which explains how the names work internally:
C# 7 ValueTuple types and their limitations | Joseph Woodward, Software Developer"[^]
Basically, the names for the fields of local variables are lost when the code is compiled. For tuples returned from methods or properties, the names are stored in an attribute on the method. The compiler "magically" rewrites access to the named members to use the Item1 , Item2 etc. properties.
There are still quite a few limitations. They might be useful for internal code, but for anything that crosses a project boundary, I'd still be inclined to use a custom type.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi, Richard, I remember reading Woodward's article earlier this year, and, in fact, a motivation for this post was his statement:Quote: This is because the ValueTuple type's named elements are erased at runtime, meaning there's no runtime representation of them. In my head this statement is incongruent with what I observe in the VTProp example above: at run-time accessing that Property returns a result that has the field Names.
Undoubtedly, it is my head that needs adjustment, not Woodward's, or yours
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
|
|
|
|
|
BillWoodruff wrote: at run-time accessing that Property returns a result that has the field Names.
No; you're accessing that named property when you're writing the code. Once the code is compiled, if you check the MSIL, you're accessing a property called Item1 .
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi, Richard, If I execute this code, using the Property shown above, 'VTProp: it compiles, and runs without error
VTProp = ("hello", 23, "exit");
var vtp = VTProp;
string s2 = vtp.S2; For me, this creates a cognitive dissonance when I read your comments,and Woodward's.
Clearly, there is a run-time mechanism for using the field Name attributes as long as you have not "vanillafied" the Types.
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
|
|
|
|
|
The property name is just syntactical sugar provided by the compiler. The only time it appears in the compiled code is in the TupleElementNames attribute.
If you were using a compiler that didn't understand that attribute - for example, ASP.NET without the Roslyn NuGet packages installed - you would only have access to the raw ItemN properties.
It's somewhat similar to how LINQ works; the compiler takes the C# code you've written, and transforms it into IL code that the JIT compiler will understand. The JIT compiler doesn't need to know anything about query statements, or extension methods, or even iterator methods.
If you use something like LINQPad[^] to examine the IL, you'll see something like this:
var vtp = VTProp;
Console.WriteLine("S2: {0}", vtp.S2); ⇒
ldarg.0
call UserQuery.get_VTProp
stloc.0
ldstr "S2: {0}"
ldloc.0
ldfld System.ValueTuple<System.String,System.Int32,System.String>.Item3
call System.Console.WriteLine ⇒
ValueTuple<string, int, string> vtp = VTProp;
Console.WriteLine("S2: {0}", vtp.Item3);
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I read what you write carefully, but, this does not address the "facts" presented by what I observe.
The digression about what will not happen in another flavor of the .NET compiler has what bearing on this topic ? Of course, new syntactic features are not available in other/previous versions of .NET.
The code I showed demonstrates the availability of ValueTuple field Names at run-time; the fact this is a result of the compiler's action, and does not show up in the IL, is understood.
There's a whole lot of .NET features that don't appear in the IL ... which seems like a like a tautology to me: what else would the IL be if it were not a distilled-to-the-metal (but, still abstracted from actual hardware) representation
Understanding how ValueTypes, and their optional field Names, work is, imho, not furthered by statements that do not match observed run-time behavior.
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
|
|
|
|
|
BillWoodruff wrote: at run-time
The point is, your C# code is not what's executing at run-time. What's executing at run-time is the (machine code compiled from the) MSIL generated by the C# compiler.
If you've ever looked at the run-time version of an iterator method, or an async method, you'll see that the run-time MSIL often bears little resemblance to the C# you wrote.
The ValueTuple field names are not available at run-time. They are only available to the Roslyn compiler.
Or perhaps I've misunderstood what you mean by the phrase "run-time"?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Richard Deeming wrote: Or perhaps I've misunderstood what you mean by the phrase "run-time"? Evidently, yes
I mean exactly what this example proves:
public (string S1, int I1, string S2) VTProp {set; get;} VTProp = ("hello", 23, "exit");
var vtp = VTProp;
string s2 = vtp.S2; At run-time the third field of the ValueTuple can be accessed by its field Name 'S2 without error.
QED
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
|
|
|
|
|
OK, we're obviously talking about different things.
At run-time - when the code is running - your C# code is nowhere in sight. All that exists is the MSIL code, which is the result of various transformations applied by the C# compiler.
The fact that you can write and compile code which uses the named field doesn't mean that the named field is available when the code is running. It just means that the compiler understands it, and knows how to transform it into something that will work at runtime.
If you want to try accessing it when the code is running, try using reflection, or dynamic . You'll see that the named field is not available.
Type t = VTProp.GetType();
Console.WriteLine(t.GetField("S2"));
foreach (FieldInfo field in VTProp.GetType().GetFields())
{
Console.WriteLine(field.Name);
}
dynamic vtp = VTProp;
Console.WriteLine("S2: {0}", vtp.S2);
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
tell me
modified 22-Feb-18 15:55pm.
|
|
|
|
|