When I am tracing, I think it would be useful to do something like
//In the main function
{
Log(myVariable);
}
Which sends the variable to a generic function like this
//In the Logger file
public static void TraceMessage<T>(T aVariable)
{
string oldName=GetOldName(aVariable);
}
I want "myVariable" to be assigned to oldName. What should GetOldName do?
Something similar was asked here:
get name of a variable or parameter
But in all of those cases, "aVariable" is assigned to oldName.
Update: Old name is what the parameter/variable was called before it was sent to the function. I use it as a variable here just for ease of explaining.
The reason for this is debugging. When my program receives an error I would like to know what the value of my variables are. I currently have to send Log(the error, the variable name, the variable value). When you write 1000 of the these Debug statements you think of ways this could be simplified. What I am asking would simplify the problem.
Why did my question get downvoted and how can I improve the question?
This information needs to be captured and provided by the caller. In C# 6, it can be easily achieved using the nameof operator, although you'll need to apply this in your caller code:
Log(myVariable, nameof(myVariable));
Edit: If you only want to specify your variable once, you can use:
Log(() => myVariable);
And define your Log method as:
public static void Log<T>(Expression<Func<T>> expression)
{
string oldName = ((MemberExpression)expression.Body).Member.Name;
object value = expression.Compile().Invoke();
}
However, this will be much slower than the alternative, and is not guaranteed behaviour.
Related
I am I am using C# 7+, and I am aware of the [CallerMemberName] attribute, but what I am looking for is an attribute that would get me the name of an argument.
Use case: Checking for null, even with the ?? and ? null operators, can be a bit tedious with the condition checks and throwing the proper exceptions with the proper values. For a few months now I've been using a solution inspired by some article I read and that could be described as an "argument validation builder". It would be used something like this:
public class MyClass
{
public void DoTheThing(IFoo foo, ICollection<IBar> bars, string specialText)
{
new ArgumentValidator()
.NotNull(foo, nameof(foo))
.NotNullOrEmpty(bars, nameof(bars))
.NotNullOrEmpty(specialText, nameof(specialText));
...rest of function
}
}
If, for example, foo was null, then ArgumentValidator.NotNull(...) would throw a new ArgumentNullException with the parameter name "foo". This approach makes argument checking a bit more concise, and that's pretty much the only reason I'm doing this.
It would be really nice if I didn't have to specify nameof(...) every single time. That is, I'd like to be able to do this:
new ArgumentValidator()
.NotNull(foo)
.NotNullOrEmpty(bars)
.NotNullOrEmpty(specialText);
In order to do that though, I would need to figure how to make the NotNull(...) and other functions figure out the name of the argument.
I've tried making a parameter-based attribute, I've tried looking at Environment.StackTrace (not thrilled about trying to parse that nor about the performance implications), I've looked at StackFrame, I've looked at getting type info about the class -> method info -> parameter info and the custom attributes, and I still haven't found a way forward.
I'd like to make an attribute similar to [CallerMemberName], but this attribute would extract the name of the argument that was used to call the function, assign it to the decorated parameter, and would performs quickly (in other words, I want to avoid stack trace stuff if possible, especially since I'm using these checks a lot).
This is where I'm at:
[AttributeUsage( AttributeTargets.Parameter )]
class ArgumentNameAttribute : Attribute
{
public string SomeProperty { get; set; }
}
class Program
{
static void NotNull<T>( T argument, [ArgumentNameAttribute] string argumentName )
{
//how to get at the argumentName?
}
static void DoTheThing( string thing )
{
NotNull( thing );
Console.WriteLine( "hello world" );
}
static void Main( string[] args )
{
DoTheThing( "12345" );
}
}
Alternately, I'll accept another solution that makes argument checking concise and expressive.
Ideas?
No one has created an answer yet, but comments have mentioned alternatives:
Aspect Oriented Programming (AOP)
Use C# 8's nullable reference type syntax
While not answering the specific question, these did answer the general intent of a cleaner way to handle null types. Considering my question answered.
I have a variable that I want to change inside a function and reflex the new change in the orginal variable . I am trying to change the original variable value to Scott inside the function and then reflex that new change outside the function:
public ActionResult HomePage()
{
string name = "John";
ChangeName(name);
string newName = name ; -- This still says John
}
public static void ChangeName(string myname)
{
myname = "Scott";
}
You can do that by passing the string by reference -
public ActionResult HomePage()
{
string name = "John";
ChangeName(ref name);
string newName = name ; -- This is now Scott.
}
public static void ChangeName(ref string myname)
{
myname = "Scott";
}
However, as stated by TheSoftwareJedi in the comments, it is usually best to avoid passing parameters by reference. Instead, you should have your method return the new string, especially considering the fact that strings are immutable, so you can't really change them, you can only change the reference to point to another string.
So a better method would be something like this:
public static string GetAnotherName()
{
return "Scott";
}
A little more in depth - there are basically two kinds of types in c# (relevant to this point, at least): There are value types like enums, structs (including all primitive types such as int, bool etc') and there are reference types (basically, everything else).
Whenever you pass an argument to a method, it gets passed by value, unless you specify the ref (or out) keyword, even if it's a reference type (in that case, the reference gets passed by value). This means that when ever you are assigning a new value to the argument inside the method, you will only see it outside the method if the argument was passed explicitly by reference (using the ref or out keyword).
The main difference between reference types and value types is that when you change the properties of a reference type inside a method, you will see the new values outside the method as well, however when you change the properties of a value type inside a method, that change will not reflect to the variable outside that method.
Jon Skeet have written a fairly extensive article about that subject, and he is way better than me in explaining things, so you should probably read it as well.
To start with, I would recommend you to read about references, values and parameters passing. There is a nice summary on this theme by Jon Skeet — Parameter passing in C# and good explanation of reference concept by Eric Lippert — References are not addresses.
You should know that by default parameters are passed by value in C#, it means parameter will contain a copy of the reference passed as argument, it means assignments will only change parameter itself and won't be observable at the call site.
That's why
myname = "Scott";
Only changes value of the method parameter myname and not the outer name variable.
At the same time, we are able to pass our variable by reference with use of ref, in or out keywords. Although in and out keywords are adding excess guarantees, which are out of theme discussed, so I'll continue with ref.
You should change both declaration of your method and call site to use it.
public static void ChangeName(ref string myname)
{
myname = "Scott";
}
And it should be invoked now as
ChangeName(ref name);
This time there is no copying, so myname parameter stores the same reference as name variable and, moreover parameter and variable are stored at one location, it means changes to myname inside ChangeName method will be visible to invoking code.
To continue with, I'd like to point you to a separate, but related theme in regards of your question — Expressions and Statements and to link you to a good article about them written by Scott Wlaschin — Expressions vs statements (there is a bit of F# inside, but that's not critical).
Generally, there is nothing wrong with approach you've selected, but it's imperative, statement based and a bit too low level. You are forced to deal with references and their values, while what you really want is just to get value "Scott" from your method. This will look more straightforward and obvious, if implemented as an expression.
public static string GetName() => "Scott";
This way code is declarative and thus more simple (and short), it directly illustrates your goals.
I am working on a c# library, so we are concerned with breaking backwards compatibility, but I was wondering is it possible to change just the name of a parameter and maintain backwards compatibility because of the ability to use named parameters? An example of what I am trying to do is below
[Obsolete("use ChangeSpecificFoo(SpecificFoo specificFoo)")]
public void ChangeSpecificFoo(SpecificFoo foo)
{
_specificFoo = foo;
}
//Compile error ... already defines a member called 'ChangeSpecificFoo' with the same parameter types
public void ChangeSpecificFoo(SpecificFoo specificFoo)
{
_specificFoo = specificFoo;
}
Just changing the parameter name runs the potential risk of breaking backwards compatibility because someone could be calling the method using named parameters like ChangeSpecificFoo(foo: someSpecificFoo) , but we can't deprecate the method by adding a new method with the correct parameter name because parameter names are not included in the method signature, so the compiler sees it as a duplicate.
Is there any way around this? The only alternatives I see are changing the method name so it is not a duplicate and then deprecating the old method, or waiting until we add or remove parameters from the parameter list and changing the parameter names then(this may never happen because the method is pretty stable), or just make the change and fix any breaks that we may have from code using this library as we find them.
My first inclination for this is simple: DON'T. The name of your parameter is irrelevant outside of the method body. You're right to consider people calling it out by name, and therefore potentially breaking it. However, just changing the name of the parameter gives no real benefit.
The only possible reason for changing the name is to redefine what the method does because the old name leads to confusion. In that case, the name of the method should also be changed in order to not introduce another form of confusion. (The fact that the method signatures are identical is the first and more important reason to not change parameter names. However, this is to potentially explain why you might want to.)
If however, you are still adamant about keeping the same method signature, but altering the name, you could do this. (Again, I'm strongly recommending you either don't change it at all, or rename the method as well to continue to eliminate confusion.)
One way around this would be to have the method with both parameters, but make the second optional. Have that last parameter use the old name, and then assign it over within the method.
I would also HIGHLY recommend logging any uses of the named parameter, to see if your concern is valid about people calling it as a named parameter.
public void ChangeSpecificFoo(SpecificFoo specificFoo = null, SpecificFoo foo = null)
{
if (foo != null && specificFoo == null)
{
// Add any other details you can, especially
// to figure out who is calling this.
Log("Someone used a name parameter!!");
}
_specificFoo = specificFoo ?? foo;
}
As Dmitry Bychenko pointed out in the comments, this will not stop anyone from calling this method like so: ChangeSpecificFoo(null, new SpecificFoo()), which will trigger a logging.
His observation introduces another reason why this is a bad idea: You're now introducing ANOTHER way for people to "incorrectly" call your method. Therefore, I'll repeat my advice from the top of my answer: DON'T do this, unless you really really really need to change that parameter name.
I recently wrote the following statement by accident.
MyCollection myCollection = new MyCollection();
SomeMethod(myCollection.SomeVoidOperation());
Stupidly it took me some time to work out why it didn't work (Had a brainfart) but then it got me thinking; why is such a statement actually invalid in any general C type syntax context?
I understand that I can accomplish the same functionality with method chaining but what I don't get is why such a feature isn't (or perhaps can't) be implemented? To me the intent seems clear and I've tried but I can't see any ambiguity it might create. I'm sure there are some good reasons (or something that I'm missing) and hopefully someone can point it out to me.
So, why can’t an operation be
performed as part of an assignment?
UPDATE:
I understand why this doesn't work. IE: I have a method that expects some parameter and I am calling a method that doesn't return anything - but you are missing my point.... I see that code as two statements one is myCollection (IE: An instance) and the second is "invoke this method".
Here is a more complete example:
public class Stock
{
public Guid ID { get; set; }
public string Description { get; set; }
}
public class StockList : List<Stock>
{
public void SomeSortOperation() { }
}
public void SomeMethod(StockList stockList)
{
}
StockList myList = new StockList();
SomeMethod(myList.SomeSortOperation());
It looks like you're trying to use the result of SomeVoidOperation as a method argument (presumably to a method with no arguments) - but presumably you're not, because it's a void method.
It's never a good idea for code to look like it's doing one thing, when it's actually doing another.
EDIT: Okay, no, having seen the edit, I still don't think this is a good idea. You're basically saying that if you try to use a void expression as a method argument, it should actually use some different value, based on the expression. That expression would have to be very carefully defined... for example, would:
Foo(x.MethodReturningBar().MethodReturningVoid());
consider the argument to be the type of x, or Bar (the return type of the intermediate method call)?
Again, you're writing code which looks like it's doing one thing (using the value of the whole expression as an argument) when it's actually doing something else (using the value of part of the expression as an argument). That's simply a bad idea.
If you mean by SomeVoidOperation() that the operation returns no value (void):
You can't pass nothing to a method that expects to get something. You can't cast a nothing to the type that SomeMethod() expects to get.
I believe that you should backtrack a little and try to understand the void type first. See this answer C# void type- safety. I believe this will give more insight in why what you're trying to do doesn't work.
This is issue about LANGUAGE DESIGN.
Please do not answer to the question until you read entire post! Thank you.
With all helpers existing in C# (like lambdas, or automatic properties) it is very odd for me that I cannot pass property by a reference. Let's say I would like to do that:
foo(ref my_class.prop);
I get error so I write instead:
{
var tmp = my_class.prop;
foo(tmp);
my_class.prop = tmp;
}
And now it works. But please notice two things:
it is general template, I didn't put anywhere type, only "var", so it applies for all types and number of properties I have to pass
I have to do it over and over again, with no benefit -- it is mechanical work
The existing problem actually kills such useful functions as Swap. Swap is normally 3 lines long, but since it takes 2 references, calling it takes 5 lines. Of course it is nonsense and I simply write "swap" by hand each time I would like to call it. But this shows C# prevents reusable code, bad.
THE QUESTION
So -- what bad could happen if compiler automatically create temporary variables (as I do by hand), call the function, and assign the values back to properties? Is this any danger in it? I don't see it so I am curious what do you think why the design of this issue looks like it looks now.
Cheers,
EDIT As 280Z28 gave great examples for beating idea of automatically wrapping ref for properties I still think wrapping properties with temporary variables would be useful. Maybe something like this:
Swap(inout my_class.prop1,inout my_class.prop2);
Otherwise no real Swap for C# :-(
There are a lot of assumptions you can make about the meaning and behavior of a ref parameter. For example,
Case 1:
int x;
Interlocked.Increment(ref x);
If you could pass a property by ref to this method, the call would be the same but it would completely defeat the semantics of the method.
Case 2:
void WaitForCompletion(ref bool trigger)
{
while (!trigger)
Thread.Sleep(1000);
}
Summary: A by-ref parameter passes the address of a memory location to the function. An implementation creating a temporary variable in order to "pass a property by reference" would be semantically equivalent to passing by value, which is precisely the behavior that you're disallowing when you make the parameter a ref one.
Your proposal is called "copy in - copy out" reference semantics. Copy-in-copy-out semantics are subtly different from what we might call "ref to variable" semantics; different enough to be confusing and wrong in many situations. Others have already given you some examples; there are plenty more. For example:
void M() { F(ref this.p); }
void F(ref int x) { x = 123; B(); }
void B() { Console.WriteLine(this.p); }
If "this.p" is a property, with your proposal, this prints the old value of the property. If it is a field then it prints the new value.
Now imagine that you refactor a field to be a property. In the real language, that causes errors if you were passing a field by ref; the problem is brought to your attention. With your proposal, there is no error; instead, behaviour changes silently and subtly. That makes for bugs.
Consistency is important in C#, particularly in parts of the language that people find confusing, like reference semantics. I would want either references to always be copy-in-copy-out or never copy-in-copy-out. Doing it one way sometimes and another way other times seems like really bad design for C#, a language which values consistency over brevity.
Because a property is a method. It is a language construct responding to a pattern of encapsulating the setting and retrieval of a private field through a set of methods. It is functionally equivalent to this:
class Foo
{
private int _bar;
public int GetBar( ) { return _bar; }
public void SetBar( ) { _bar = value; }
}
With a ref argument, changes to the underlying variable will be observed by the method, this won't happen in your case. In other words, it is not exactly the same.
var t = obj.prop;
foo(ref t);
obj.prop = t;
Here, side effects of getter and setter are only visible once each, regardless of how many times the "by-ref" parameter got assigned to.
Imagine a dynamically computed property. Its value might change at any time. With this construct, foo is not kept up to date even though the code suggests this ("I'm passing the property to the method")
So -- what bad could happen if
compiler automatically create
temporary variables (as I do by hand),
call the function, and assign the
values back to properties? Is this any
danger in it?
The danger is that the compiler is doing something you don't know. Making the code confusing because properties are methods, not variables.
I'll provide just one simple example where it would cause confusion. Assume it was possible (as is in VB):
class Weird {
public int Prop { get; set; }
}
static void Test(ref int x) {
x = 42;
throw new Exception();
}
static void Main() {
int v = 10;
try {
Test(ref v);
} catch {}
Console.WriteLine(v); // prints 42
var c = new Weird();
c.Prop = 10;
try {
Test(ref c.Prop);
} catch {}
Console.WriteLine(c.Prop); // prints 10!!!
}
Nice. Isn't it?
Because, as Eric Lippert is fond of pointing out, every language feature must be understood, designed, specified, implemented, tested and documented. And it's obviously not a common scenario/pain point.