Re: Avoiding Default Parameter Checking in C# 4.0
- From: Peter Duniho <no.peted.spam@xxxxxxxxxxxxxxxxxx>
- Date: Thu, 03 Dec 2009 16:38:16 -0800
jehugaleahsa@xxxxxxxxx wrote:
I can call a public method in one class from another. The policy is/
was specific to in-class method calls.
I think we all understood that much.
I typically reserve public
methods for argument checking, exception handling and resource
management.
So, none of your in-class code gets these benefits? Seems like that would only increase overhead elsewhere, either in maintenance or duplicated code.
Then they just call a private method. The private method
stays really pure and simple, which makes it extremely readable.
Occasionally an exception needs thrown in the middle of the private
implementation, but this is a rare case.
The original reason, in the case of my Compass library, was because I
didn't want to hurt performance performing unnecessary argument
checks.
I find this comment ironic. It seems to me that the rule to never call public methods from within the class leads to extra method calls, itself a potential "performance hurting" operation. Performance-wise, it seems that if one has to choose between checking for a null pointer and making two method calls where one would suffice, the former would be preferable. (Granted, that may not be the specific pair of choices one is presented with...the example is just for the point of comparison).
For instance, I have a ToIList method which converts an
IEnumerable<T> to an IList<T> (using "as" to see whether it is
already one first). I do a check to see whether the IEnumerable<T> is
null and whether it is an instance of IList<T>.
I'm confused by your description of this method. It sounds like you have a method that does basically what the "as" operator does, except that it somehow fails (throws an exception?) if you pass it "null"? And presumably it also fails somehow if the object doesn't implement IList<T> (also an exception?).
What is this method doing, other than creating a situation where you could have a variable typed as IList<T> and fail to convert the value of that variable to an IList<T>? For example:
IList<T> ToIList<T>(IEnumerable<T> e)
{
IList<T> l = e as IList<T>;
if (e == null || l == null)
throw new InvalidArgumentException();
return l;
}
void MethodA()
{
MethodB(null);
}
void MethodB<T>(IList<T> l)
{
MethodC(l);
}
void MethodC(IEnumerable<T> e)
{
IList<T> l = ToIList(e);
}
The example is only slightly contrived, in that I've explicitly created a sequence of calls guaranteed to fail. Real-life code could legitimately have a null reference in a variable rather than a hard-coded value.
In any case...
If I am calling it
from a method where I know for sure that the IEnumerable<T> is not
null and that it is not IList<T>, why pay for the runtime overhead?
If you already know it's NOT an IList<T>, why would you call such a method at all, regardless of whether it has argument checking or not?
In any case, the more direct answer to your question is: because it complicates the code, and creates runtime overhead for other scenarios (an extra method call for any callers of the public, argument-checking version).
Basically, your in-class code avoids a little bit of overhead, but it forces your client code to suffer _two_ forms of overhead instead of just one.
There are also occasions where I want a method to be available for
both .NET 1 and beyond. So, if I am working with an IEnumerable<T> and
an IEnumerable, I will create a private method:
int count(IEnumerator enumerator)
{
int count = 0;
while (enumerator.MoveNext())
{
++count;
}
return count;
}
I call this method with a generic and non-generic version as so:
int Count<T>(IEnumerable<T> collection)
{ // argument check
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{ return count(enumerator); }
}
int Count(IEnumerable collection)
{ // argument check
return count(collection.GetEnumerator());
}
First, there's already an IEnumerable<T>.Count() extension method. Why write your own? (Especially since the extension method is clever enough to not actually enumerate the entire collection if there's a Count property it can retrieve).
Second, IEnumerable<T> implements IEnumerable. So you don't need a third method for the purpose. You can just have your Count<T>() method call your Count() method and put the implementation there:
int Count<T>(IEnumerable<T> collection)
{
return Count((IEnumerable)collection);
}
int Count(IEnumerable collection)
{
int iRet = 0;
foreach (object obj in collection)
{
iRet++;
}
return iRet;
}
Note that there's also no need to get the enumerator itself. Let the language take care of that for you with the "foreach" statement.
In any case, I don't see how that example explains a policy of never calling a class's public methods from within the class.
Pete
.
- Follow-Ups:
- Re: Avoiding Default Parameter Checking in C# 4.0
- From: jehugaleahsa@xxxxxxxxx
- Re: Avoiding Default Parameter Checking in C# 4.0
- References:
- Avoiding Default Parameter Checking in C# 4.0
- From: jehugaleahsa@xxxxxxxxx
- Re: Avoiding Default Parameter Checking in C# 4.0
- From: Peter Duniho
- Re: Avoiding Default Parameter Checking in C# 4.0
- From: jehugaleahsa@xxxxxxxxx
- Re: Avoiding Default Parameter Checking in C# 4.0
- From: Harlan Messinger
- Re: Avoiding Default Parameter Checking in C# 4.0
- From: jehugaleahsa@xxxxxxxxx
- Avoiding Default Parameter Checking in C# 4.0
- Prev by Date: Re: Path
- Next by Date: Re: XML vs SQL Server
- Previous by thread: Re: Avoiding Default Parameter Checking in C# 4.0
- Next by thread: Re: Avoiding Default Parameter Checking in C# 4.0
- Index(es):
Relevant Pages
|