Resharper structural find and replace with objects - c#

I use a library which provides a custom fluent implementation for string.Format. The idea is to replace the common format construct with one that reads in a more natural way like this:
// From this
string.Format("some format string with {0} parameter", 1);
string.Format(SomeConstant, "abc");
// To this
"some format string with {0} parameter".Format(1);
SomeConstant.Format("abc");
I was trying to setup a simple structural find and replace pattern in Resharper to help me deal with those inside my code base. I noticed that if I set the format string parameter as an Argument Placeholder matching exactly one argument and the list of arguments uses entity objects (like a Person object), the previous example would turn into:
// Note that this is the System.String class and not the original format string
String.Format(someEntity);
If the entity is first converted to a string, then it matches properly and keeps the format string as I would expect.
SomeConstant.Format(someEntity.ToString());
I had to use an Expression Placeholder with an expression type of System.String to properly match the first parameter.
Is this a bug or is there something that I am not understanding in this behavior? Why would the type of the second argument influence the match of the first argument? I have a feeling that I might be misunderstanding how Argument Placeholders are working...
NB: Using Resharper 9.0 Update 1
EDIT: As requested, here is the search pattern details:
Search Pattern: String.Format($format$, $args$)
Replace Pattern: $format$.Format($args)
format: Argument Placeholder, matching exactly one argument
args: Argument Placeholder, matching at least one argument

Related

C# Dynamic Linq: Strings are assumed to be integers?

I'm using the System.Linq.Dynamic library found here, which is simply an upload of Microsoft's library to be accessible via NuGet: https://github.com/kahanu/System.Linq.Dynamic
In my code, I have this function that gets a list of objects from a database that match a certain property. It needed to be as flexible as possible, so the parameters consist of three strings;
One for the "order by" statement
One for the property to match's name
One for the expected property's value
Here's the line of code that's giving me trouble:
public IQueryable<T> GetByProperty(string propertyName, string propertyValue,
string orderStatement)
{
return _context.Set<T>()
.OrderBy(orderStatement)
.Where(propertyName + " = " + propertyValue);
}
Here are the possible scenarios;
propertyValue contains only numbers: the query works perfectly.
propertyValue starts with numbers but has letters in it: the following error appears: Operator '=' incompatible with operand types 'String' and 'Int32'
propertyValue is anything else: the following error appears: No property or field '[the first part of the "propertyValue string, up until it meets an empty space, a "-" or some other specific characters]' exists in type '[Class name of <T>]'
I've tried using single quotes to surround my string, but I then get the error: 'Character literal must contain exactly one character'
I've also desperately tried to add ".ToString()" at the end to try and trick something into working, but I found the error: Digit expected.
Is there another way to use the "Where" clause, in Linq and Dynamic Linq, that would support the flexibility I'm trying to have using this structure?
You need to know the type of the property and format the value accordingly. If it is a string, enclose it in double quotes. i.e. name = "John" but age = 20.
It does not depend whether the value looks like a number or not.
If the type of the property is a number type then the value must be a number as well and not be enclosed in quotes.
If the type of the property is a string then the value must be enclosed in double quotes, even if the value is a number (e.g. code = "3").

Is there a way to trim leading characters using String.Format()?

Need to know of there is a way to use String.Format to remove leading characters from a string. I have a limitation in some existing code that I can only pass in a string and a format string for it.
So can you do something like
String.Format("Test output: {0:#}","001")
and produce the output
"Test output: 1"
I think the answer is 'No' but I wanted to make sure.
EDIT: To clarify, the format string will be put in a configuration file and the string to be formatted is a value coming out of a database. I can't execute any code on it. Has to be through the format string.
You could do it on the arg you are passing
String.Format("Test output: {0:#}", "001".TrimStart('0'))
Alternatively you could probably do a find with replace using a regular expression on the resulting string.
An other alternative is to define and pass in your own formatter using a custom implementation of IFormatProvider. I am not sure if this is allowed or not based your your last edit.
However, based on the restrictions listed, there is no way to do it with just the format string input

Why root symbol does not works in hyper link when returned by an expression?

Just a thought came in mind.
Why the first of these two tags does not work in asp.net?
To me both are string values whose final value is same. Which is value of attribute href of hyperlink.
Please make me understand it.
Test
Test
Note: I am not looking for solution to it. Only want to understand what's logically difference between these two case.
To me both are string values whose final value is same
Not really. Consider first if you just had a plain non-razor HTML form such as if you'd hard-coded the beginning of the path:
Test
Now, here "/SomeProject/Test/Index" is not a string. It's an attribute value in HTML. HTML has no concept of "string". Sure it happens to use the same delimiter as C# does for string, but this isn't C# here.
With Razor we have a few means to indicate we want something done by Razor to the otherwise plain HTML.
# is one of them, indicating that we want a C# expression evaluated and the result (if not void) output. And the result of (string.Format("~/Test/Index")) is ~/Test/Index so that is output.
~/ is, in certain contexts, another one, indicating that it should be replaced with the value of evaluating Href("~/") or Url.Content("~/"), which would be something like / or /SomeProject/ or whatever. It's not so much a string as something more like a keyword.
If you have an expression returning a string, you can still use strings similarly with:
Test
Which incidentally, was the only way this could be done in Razor 1.0. The direct parsing of "~/… was added as a convenience and it is indeed convenient.
I think you're misunderstanding what string.Format(string format, params Object[] args) does. It will only replace specified placeholders {0}, {1}, etc with provided paramters. Take a look at the docs in the link provided for more info.
In short it doesn't do any automatic replacement of environment variables or any other substitutions not already covered by the placeholders.
String.Format sits in the System namespace, therefore I wouldn't expect it to know anything about web sites, file systems or anything more complicated than simple placeholder substitution and formatting.
You should be using Url.Action i.e.
Test
or even easier
#Html.ActionLink("Test", "Index", "Test")
Also note that in ASP.Net MVC you don't use the full controller name, only the prefix i.e. Test instead of TestController

.Net regex not replacing correctly

Background
I am trying to do some regex matching and replacing, but for some reason the replacement isn't correct in .NET.
Regex pattern - "^.*?/rebate/?$"
Input string - "/my-tax/rebate"
Replacement string - "/new-path/rebate"
Basically, if the word 'rebate' is seen in a string, the input string needs to be replaced entirely by the replacement string.
Problem
If I create a regex with the pattern and execute
patternMatch.Pattern.Replace("/my-tax/rebate", "/new-path/rebate")
I get /my-tax/new-path/rebate, which isn't correct.
But, if I execute -
new Regex(#"^.*?/rebate/?$").Replace("/my-tax/rebate", "/new-path/rebate"),
the result is correct - /new-path/rebate
Why is that?
patternMatch is an object with two properties - one Pattern (which is the Regex Pattern) and another one is TargetPath (which is the replacement string). In this example, I am only using the pattern property.
patternMatch.Pattern on debugging is
Here are the results during run time-
You are simply wrongly using the function. I'm not sure how you are getting /my-tax/new-path/rebate since it is giving me an error on ideone.com (Maybe you have a regex named Pattern?).
Anyway, you shouldn't have any issues with using the function like this:
patternMatch.Replace("/my-tax/rebate", "/new-path/rebate");
ideone demo
A number of points in your question are incorrect. The regex is replacing correctly.
Per #XiaoguangQiao's comment, what is patternMatch.Pattern.Replace? Your example...
var patternMatch = new Regex("^.*?/rebate/?$");
patternMatch.Pattern.Replace("/my-tax/rebate", "/new-path/rebate");
...errors with the message...
'System.Text.RegularExpressions.Regex' does not contain a definition for 'Pattern' and no extension method 'Pattern' accepting a first argument of type 'System.Text.RegularExpressions.Regex' could be found
...when I throw it into a quick LINQPad 4 query (set to C# Statement(s)).
pattern is a private string field of System.Text.RegularExpressions.Regex; and patternMatch.Replace("/my-tax/rebate", "/new-path/rebate") - which I expect is what you meant - yields the correct result ("/new-path/rebate") rather than the incorrect result you said you get ("/my-tax/new-path/rebate").
Otherwise your pattern(s) (i.e. with and without the extra / that #rene pointed out) is fine for the input ("/my-tax/rebate") and replacement ("/new-path/rebate") you initially outline - insofar as they match and yield the result you want. You can check this outside your code in quick fiddles with the extra / and without the extra /.
Use String.Replace Method.
str.replace("rebate","new-path/rebate")
http://msdn.microsoft.com/en-us/library/fk49wtc1%28v=vs.110%29.aspx

Resharper find pattern and replace - how to insert strings

We have a sanity check method
void IsNotNull<T>(T obj){...}
invocation
IsNotNull(obj);
I want to replace this to invoke the other overload that takes a second param of type string (message)
void IsNotNull<T>(T obj, string message){...}
So I want to change the invocation as
IsNotNull(obj, "obj is null");
I'm trying to achieve this using resharper's find pattern and replace.
So my find pattern is : IsNotNull($args$) - This works fine and it finds the method calls
Replace pattern: IsNotNull($args$, "$args$ is null") - This doesn't do anything
I also tried this IsNotNull($args$, """" + $args$ + """")
--Edited--
The suggestion box showing the correct wording(for both argument and identifier), but once applied it's different. I'm using Resharper 6
After applying the suggestion I get this
When I click Edit Pattern
What is your $args$ parameter defined as in the Search and Replace? If you make it to be Identifier, then you replace should work:
Find: IsNotNull($args$) - where $args$ is an Identifier
Replace: IsNotNull($args$, "$args$ is null")
You should have the result you want, i.e. IsNotNull(obj, "obj is null").
You can consider trying to use this pattern:
IsNotNull($args$, string.Format("{0} is null", $args$))
It works perfectly for me with ReSharper 7.1.
It seems, that R# doesn't want to evaluate argument expression inside of string literals normally. Given your pattern
IsNotNull($args$, "$args$ is null")
It replaced IsNotNull(5); by IsNotNull(5, 5); which is odd
The easiest method would be to rewrite the original method like so:
void IsNotNull<T>(T obj){
IsNotNull(obj, "obj is null");
}
Then click on the method signature, and choose Refactor->Inline Method (Ctrl+R, Ctrl+I). If you need to keep the original method signature around, you can, or you can check the box for "Remove inlined method declaration."
EDIT: Looks like hmemcpy's solution works in 7.1, so I'd suggest an upgrade. If that's not possible, however, try the following regular expression find-and-replace in Visual Studio.
Find: IsNotNull\(([^\),]+)\);
Replace: IsNotNull($1, "$1 is null");
Make sure "Use Regular Expressions" is checked, and "Look in:" should be "Entire Solution".

Categories

Resources