|
Is the "params" keyword not just "syntactic sugar" for passing an arbitrary number of parameters into what is really just an array?
When you write something like:
void f(params int[] values)
{
}
void g()
{
f(3, 4, 5, 6);
f(new int[] { 3, 4, 5, 6 });
}
The two calls to "f" do exactly the same thing, the first just looks neater. I'd imagine multiple functions with different numbers of "value" arguments wouldn't be generated by the compiler, because (correct me if I'm wrong) it's more efficient to pass an array of values than to pass the values on the stack individually.
Even if the disassembler didn't understand the presence of the "params" keyword, the function signature would still have a single "int[]" parameter, wouldn't it? since the compiler didn't actually go through and generate separate functions for those parameters.
|
|
|
|
|
alcexhim wrote: Even if the disassembler didn't understand the presence of the "params" keyword, the function signature would still have a single "int[]" parameter, wouldn't it? since the compiler didn't actually go through and generate separate functions for those parameters. |
That's probably true, of course. Perhaps Microsoft did code it with eight different entry points like that. If I was the manager over the person that did that, though, said person would be on the unemployment line or in a remedial C# class! What if I have nine arguments to pass? SOL I guess!
The params argument is, yes I'm sure, syntactical "sugar" as you state but nevertheless it's still preferable than generating eight separate signatures, wouldn't you agree? It also makes life a little easier coding the call to the function. You might actually want to pass multiple arguments (in differing numbers of arguments) in different sections of code and not be constrained to create the array from the calling code. This would be particularly true if your code is passing constants in the formal parameter list. Either way, though, it's just another convenient little shortcut provided by the language.
-cb
|
|
|
|
|
Quote: If I was the manager over the person that did that, though, said person would be on the unemployment line or in a remedial C# class!
Don't be so fast with such statements. Have you tested your approach? I made a quick test and the params keyword introduces a really big performance penalty (more than factor 5, probably even 10). The reason is probably that for each call an array must be instantiated.
If I was your manager, and you would implement it that way although it could be done more than 5 times faster, than you would probably be on the unemployment line .
Also note that this functions are internal functions of the generic Tuple classes. Tuple has at most 8 generic type parameters (and as a consequence 8 properties where hash codes might get combined), so combining 9 hash codes is really not an issue here.
|
|
|
|
|
Robert Rohde wrote: Don't be so fast with such statements. Have you tested your approach? I made a quick test and the params keyword introduces a really big performance penalty (more than factor 5, probably even 10). The reason is probably that for each call an array must be instantiated.
LOL ... I hadn't thought about that! Good point. No ... I hadn't gone through a rigorous test of the code performance. If the performance loss in my approach is that bad then, yes, it's better to have the eight entry points. I stand corrected.
Too bad, though, that a convenient construct like that isn't optimized for performance because it is an obvious case where you would want to use something like that. I'm sure it could be optimized. Doesn't seem like it would be hard to get it to assemble down to a simple stack pointer movement to make room for the params argument. Whatever ...
-CB
modified 18-Apr-12 17:39pm.
|
|
|
|
|
Nope - the original code from the framework reference source is:
internal static int CombineHashCodes(int h1, int h2) {
return (((h1 << 5) + h1) ^ h2);
}
internal static int CombineHashCodes(int h1, int h2, int h3) {
return CombineHashCodes(CombineHashCodes(h1, h2), h3);
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4) {
return CombineHashCodes(CombineHashCodes(h1, h2), CombineHashCodes(h3, h4));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), h5);
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7, int h8) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7, h8));
}
The original code from System.Web.Util.HashCodeCombiner is:
internal static int CombineHashCodes(int h1, int h2) {
return ((h1 << 5) + h1) ^ h2;
}
internal static int CombineHashCodes(int h1, int h2, int h3) {
return CombineHashCodes(CombineHashCodes(h1, h2), h3);
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4) {
return CombineHashCodes(CombineHashCodes(h1, h2), CombineHashCodes(h3, h4));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), h5);
}
Good job they put all those helpful comments in to explain their choice!
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Sheesh! So much for code elegance!
|
|
|
|
|
If that is implemented in F# originally (or was compiled by a compiler that supports tail recursion), then there is no additional funciton overhead.
In fact, if the code is reordered correctly, it's faster than a loop.
The guy who wrote it probably knew a lot more about what he was doing than it appears at first glance.
|
|
|
|
|
Assert.IsFalse(!CallMethod()); Only the method name changed to protect the (not so) innocent.
|
|
|
|
|
HEY! You left out the important part! Did the test pass?
Attempting to load signature...
A NullSignatureException was unhandled.
Message: "No signature exists"
All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value.
Carl Sagan
|
|
|
|
|
No test ain't gonna fail on my watch
I'm invincible, I can't be vinced
|
|
|
|
|
|
Initially, the success of running test was !true . After some work, it is !false .
|
|
|
|
|
|
|
The horror is allowing creation of a view with an order by in the first place.
Just say no.
|
|
|
|
|
My thoughts exactly.
Chris Meech
I am Canadian. [heard in a local bar]
In theory there is no difference between theory and practice. In practice there is. [Yogi Berra]
posting about Crystal Reports here is like discussing gay marriage on a catholic church’s website.[Nishant Sivakumar]
|
|
|
|
|
Well, Order By is of some use, even in views.
But it should ALWAYS be paired with a TOP(X).
SELECT TOP 100 PERCENT *
FROM Somewhere
ORDER BY whatever
is a true, classic, horror.
|
|
|
|
|
Doing some maintenance on an application which I developed a few years ago, I found a small gem:
public string formatDateMySQL(DateTime date)
{
StringBuilder strTmp = new StringBuilder(date.Year.ToString());
strTmp.Append("-");
strTmp.Append(date.Month.ToString());
strTmp.Append("-");
strTmp.Append(date.Day.ToString());
return strTmp.ToString();
}
Yeah, formatting DateTime values works different everywhere, and that's a very "clever" way of coping with that...
License: You may use this code according to the CodeProject license.
|
|
|
|
|
Shirley AppendFormat is the way to go.
|
|
|
|
|
No, but ISO-8601 is IIRC.
|
|
|
|
|
Bernhard Hiller wrote: License: You may use this code according to the CodeProject license.
Don't you mean, "License: You must never use this code under penalty of tar-and-feathering"?
|
|
|
|
|
Just wait a little, and you'll see it becoming the solution for date/time formatting problems with MySQL server in Quick Answers...
|
|
|
|
|
Is this written in C#? I guess the more simpler way would be.
date.ToString("yyyy-MM-dd") out puts the date as 2012-04-18
or
date.ToString("yyyy-M-dd") out puts the date as 2012-4-18
If not C# Kudos to you
Sastry
|
|
|
|
|
ServiceCallInfo is actually a DataContract.
Yes... I have actually implemented a service that can call any other service it happens to find in it's configuration.
I'm sure none of this would be necessary in a dynamic language like Ruby, however what other framework/language provides such a comprehensive and flexible service framework like WCF?
I wasn't sure if this should go in "Clever Code" or "Hall of Shame" for it's meta-ness. I put it here, because I like to doubt myself
Right now it depends on all the service contracts being contained in one interface assembly though... I suppose I could also pass in the assembly name containing the contract and have it dynamically try to find or load the assembly too. Or would that be too far?
internal class ReflectedServiceChannelMethod
{
private static readonly Assembly InterfaceAssem = Assembly.GetAssembly(typeof(IGeneralLookupService));
private readonly Type _contractType;
private readonly Type _channelFactoryType;
private readonly object _channelFactory;
private readonly MethodInfo _createChannelMethod;
private readonly MethodInfo _callMethodInfo;
private readonly ParameterInfo[] _methodParams;
public ReflectedServiceChannelMethod(string interfaceName, string methodName)
{
_contractType = _interfaceAssem.GetType(interfaceName);
_channelFactoryType = typeof(EdsChannelFactory<>).MakeGenericType(_contractType);
_callMethodInfo = _contractType.GetMethod(methodName);
_methodParams = _callMethodInfo.GetParameters();
var channelFactoryConstructor = _channelFactoryType.GetConstructor(new Type[] {});
_channelFactory = channelFactoryConstructor.Invoke(new object[] {});
_createChannelMethod = _channelFactoryType.GetMethod("CreateDefaultChannel", new Type[]{});
}
public object CallService(ServiceCallInfo job)
{
object channel = null;
try
{
channel = _createChannelMethod.Invoke(_channelFactory, new object[] { });
var parameters = new List<object>();
foreach (var methodParam in _methodParams)
{
object value = null;
var paramType = methodParam.ParameterType.MakeByValType();
if (job.Parameters != null)
{
ParameterInfo param = methodParam;
var jobParam = job.Parameters.FirstOrDefault(p => p.Name == param.Name);
if (jobParam != null)
{
value = jobParam.Value;
}
if (paramType != typeof(string))
{
value = Convert.ChangeType(value, paramType);
}
}
parameters.Add(value);
}
return _callMethodInfo.Invoke(channel, parameters.ToArray());
}
catch (Exception ex)
{
ex.LogAsCritical();
return null;
}
finally
{
if (channel != null)
{
((IDisposable) channel).Dispose();
}
}
}
}
modified 29-Mar-12 14:07pm.
|
|
|
|
|
ObjectServiceFactoryServiceObjectAutomationLinkFactoryServiceFactoryObjectMetaObjectBuilderFactory .
Software Zen: delete this;
|
|
|
|
|