0

Disadvantages of the current implementation:

  • They violate the DRY principle as you have to rewrite the parameters everywhere you need them
  • They ruin implementation-hiding as you have to specify those parameters already in the interface - even if only a single one of your interface implementation needs them
  • They soil your interface, users see them in auto-complete, documentation, etc. pp.

Why have the language designers decided against something much more useable like:

public void Foo()
{
    Console.WriteLine(CallerInformation.File);
}

I guess that this implementation lacks some features: e.g. if Foo() is a class implementing IFoo and IFoo is in another assembly, how should any caller of IFoo know at compile-time that the information is required - he can't know that.

But! Isn't it better to document that this works only within one "build step" instead of producing something unusable as the current implementation?

Q1: Is there official documentation about why it is implemented the way it is now?

Q2: Does anybody know of a better solution in other languages?

D.R.
  • 20,268
  • 21
  • 102
  • 205
  • 1
    How exactly would `CallerInformation.File` actually work? Would you populate it for *every single call* at execution time? How would you propagate it through multiple methods? The current implementation has basically *no* execution-time cost. If you're going to propose an alternative, you need to be a lot clearer about how it would actually work. – Jon Skeet Jul 29 '13 at 21:28
  • Currently a caller knows about "his duty" because of some attribute. Why not at least use a method-level attribute instead of the parameter-level attributes to prevent interface-soiling? (I'm aware it does not remove all of my disadvantages) – D.R. Jul 29 '13 at 21:31
  • Well it's providing a value *for a parameter*. Would the method-level attribute have to name the parameter it applied to? Sounds a bit icky. While I can see the downsides you mention, I don't think you've proposed anything better so far. – Jon Skeet Jul 29 '13 at 21:40
  • The method level parameter would not have to name any parameter, instead, it would just inform the caller to place his location into the CallerInformation.File (which should be placed somwhere in Thread.CurrentThread.CallerInformation to prevent threading problems). This would at least prevent disadvantages 1 & 3. – D.R. Jul 29 '13 at 21:43
  • And then how would I pass "my caller" on to something else (which would normally autopopulate the info), to effectively skip a level? – Jon Skeet Jul 29 '13 at 21:46
  • Why would I want to do that? Why would I want to allow caller-faking over a nice interface? – D.R. Jul 29 '13 at 21:48
  • So that one logging overload can call another seamlessly, basically. – Jon Skeet Jul 29 '13 at 21:49
  • In that case I would recommend all the log functions calling the same private function. Better to have the not-so-nice code within the implementation of my `Logger` class (which I can test thoroughly) instead of soiling the interface with three optional parameters (probably ruining overloads anyways). – D.R. Jul 29 '13 at 21:52
  • I think we'll have to agree to disagree. I think it's a useful option to have available - and I don't think you're going to find any authoritative answers here. – Jon Skeet Jul 29 '13 at 21:59

1 Answers1

0

Caller information attributes are semantically related to method arguments (Like 'If no value is specified for this string parameter, then put the caller member name in it instead of using null as a default value'), hence I see no reason why they shouldn't be related also syntactically as it currently is.

They violate the DRY principle as you have to rewrite the parameters everywhere you need them

Other approaches would also need to do something each time it wants to assign the caller member name to a variable, like: param = param ?? SomeExpressionToGetSomeValue

They ruin implementation-hiding as you have to specify those parameters already in the interface - even if only a single one of your interface implementation needs them

Regarding implementation-hiding: It is the duty of the caller to provide arguments, so this should be in the interface (unless the runtime decides to always provide such info in all calls which would be like implicitly providing arguments - and providing arguments implicitly/magically behind the scenes doesn't seem like a better approach to me)

Regarding having to specify to specify those parameters already in the interface - even if only a single one of your interface implementation needs them: Only specify the attribute and the parameter if it is needed. This is why Math.Abs is declared as public static int Abs(int value) and not as public static int Abs(int value, object ThisIsNotNeededButLetsJustHaveItHereItAnyways)

They soil your interface, users see them in auto-complete, documentation, etc. pp.

Hmmmm I can't see why you think that's a bad thing - if the caller should supply its name, it should be in documentation etc.


What you seem to suggest yourself is something like reading stack frames, and this will compile and run but might not do what you expect:

private void SomeMethod()
{
    return new StackFrame(1).GetMethod().Name;
}

The above code will get the name of the caller at runtime, but it might not be the same as the name of the caller at compile time due to inlining or tail call optimization.

Hence, if the method wants caller information as it is during compile time (not runtime), such an approach wouldn't work.

lightbricko
  • 2,649
  • 15
  • 21