For example, I need to see if a string contains a substring, so I just do:
String helloworld = "Hello World";
if(helloworld.Contains("ello"){
//do something
}
but if I have an array of items
String helloworld = "Hello World";
String items = { "He", "el", "lo" };
I needed to create a function inside the String class that would return true if either of
the items inside the array is contained in the string, for example.
I would like to override the function Contains(string) with Contains(IEnumerable) for this scenario, instead of creating a function in another class. Is it possible to do this, and if so, how can we override the function? Thank you very much.
So here goes the complete solution (thanks guys):
public static bool ContainsAny(this string thisString, params string[] str) {
return str.Any(a => thisString.Contains(a));
}
You can't override the function, but you can make an extension method for this:
public static class StringExtensions {
public static bool ContainsAny(this string theString, IEnumerable<string> items)
{
// Add your logic
}
}
You'd then call this just like a normal method on a string, provided you reference the assembly and include the namespace:
String helloworld = "Hello World";
String[] items = new string[] { "He", "el", "lo" };
if (helloworld.ContainsAny(items)) {
// Do something
}
(Granted, you could call this "Contains", like the standard string method, but I would prefer to give it a more explicit name so it's obvious what you're checking...)
Why not keep things simple and use the Any extension method?
string helloworld = "Hello World";
string[] items = { "He", "el", "lo" };
if (items.Any(item => helloworld.Contains(item)))
{
// do something
}
Related
ok - tried looking /reading and not sure i have an answer to this.
I have a Utility class which wraps a static ConcurrentLinkedQueue internally.
The utility class itself adds some static methods - i dont expect to call new to create an instance of the Utility.
I want to intercept the getProperty calls the utility class - and implement these internally in the class definition
I can achieve this by adding the following to the utility classes metaclass, before i use it
UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure.'Each'
however what i want to do is declare the interception in the class definition itself. i tried this in the class definition - but it never seems to get called
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
i also tried
static def getProperty (String prop) { println "accessed $prop"}
but this isnt called either.
So other than adding to metaClass in my code/script before i use, how can declare the in the utility class that want to capture property accesses
the actual class i have looks like this at present
class UnitOfMeasure {
static ConcurrentLinkedQueue UoMList = new ConcurrentLinkedQueue(["Each", "Per Month", "Days", "Months", "Years", "Hours", "Minutes", "Seconds" ])
String uom
UnitOfMeasure () {
if (!UoMList.contains(this) )
UoMList << this
}
static list () {
UoMList.toArray()
}
static getAt (index) {
def value = null
if (index in 0..(UoMList.size() -1))
value = UoMList[index]
else if (index instanceof String) {
Closure matchClosure = {it.toUpperCase().contains(index.toUpperCase())}
def position = UoMList.findIndexOf (matchClosure)
if (position != -1)
value = UoMList[position]
}
value
}
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
//expects either a String or your own closure, with String will do case insensitive find
static find (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def inlist = UoMList.find (matchClosure)
}
static findWithIndex (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
else if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def position = UoMList.findIndexOf (matchClosure)
position != -1 ? [UoMList[position], position] : ["Not In List", -1]
}
}
i'd appreciate the secret of doing this for a static utility class rather than instance level property interception, and doing it in class declaration - not by adding to metaClass before i make the calls.
just so you can see the actual class, and script that calls - i've attached these below
my script thats calling the class looks like this
println UnitOfMeasure.list()
def (uom, position) = UnitOfMeasure.findWithIndex ("Day")
println "$uom at postition $position"
// works UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure[4]
println UnitOfMeasure.'Per'
which errors like this
[Each, Per Month, Days, Months, Years, Hours, Minutes, Seconds]
Days at postition 2
Years
Caught: groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
at com.softwood.scripts.UoMTest.run(UoMTest.groovy:12)
Static version of propertyMissing method is called $static_propertyMissing:
static def $static_propertyMissing(String name) {
// do something
}
This method gets invoked by MetaClassImpl at line 1002:
protected static final String STATIC_METHOD_MISSING = "$static_methodMissing";
protected static final String STATIC_PROPERTY_MISSING = "$static_propertyMissing";
// ...
protected Object invokeStaticMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter) {
MetaClass mc = instance instanceof Class ? registry.getMetaClass((Class) instance) : this;
if (isGetter) {
MetaMethod propertyMissing = mc.getMetaMethod(STATIC_PROPERTY_MISSING, GETTER_MISSING_ARGS);
if (propertyMissing != null) {
return propertyMissing.invoke(instance, new Object[]{propertyName});
}
} else {
// .....
}
// ....
}
Example:
class Hello {
static def $static_propertyMissing(String name) {
println "Hello, $name!"
}
}
Hello.World
Output:
Hello, World!
I am building a automated swagger plugin. Here I run through annotated classes.
When we talk about the datatypes of String, Long, etc. is is enough for me use the simpleName method.
But when get to a Class of List, Set, Collection I need to know the generic type.
So how can I do this?
A example of code which do most of the job:
class Foo {
List<String> myString
}
class SomeUtilClass {
static String dataType(Class<?> c) {
return c.simpleName
}
static List<String> dataTypes(Class<?> c) {
return c.metaClass.properties.findAll {MetaProperty metaProperty ->
metaProperty?.field != null
}.collect {dataType(it.type)}
}
}
SomeUtilClass.dataTypes(Foo) // ["List"] but I want something like ["List<String>"]
I found the solution. I can look on the generic type from Cached fields.
See below example:
class SomeUtilClass {
static String dataType(Class<?> c) {
return c.simpleName
}
static List<String> dataTypes(Class<?> c) {
return c.metaClass.properties.findAll {MetaProperty metaProperty ->
metaProperty?.field != null
}.collect {findGenerics(it.type)}
}
static void findGenerics(CachedField t) {
t.field.genericType?.actualTypeArguments.collect {dataType(it)}
}
}
I understand calling a base method with arguments will default to the method without any default parameters. Great! Fully understandable!
Resolving Ambiguities with Optional Parameters and Named Arguments
However, consider this scenario
using System;
class Class1 {
public virtual string method1( string test ) {
return test;
}
}
class Class2 : Class1 {
// Method is hidden!
public override string method1( string test ) {
return test;
}
public virtual string method1( string test, string test2 = " - this shouldn't be called" ) {
return test + test2;
}
}
class Class3 : Class2 {
static int Main( string[] args ) {
var c = new Class3();
string theString;
theString = c.test1();
System.Console.WriteLine( theString ); // "Test - this shouldn't be called"
theString = c.test2( );
System.Console.WriteLine( theString ); // "Test"
return 0;
}
public string test1() {
return base.method1( "test" ); // calls base.method1( string, string )
}
public string test2() {
return ( ( Func<string, string> )base.method1)("test"); // calls base.method1( string )
}
}
Clearly the intended behavior of calling the base method should only print out "Test" but it does not and instead calls the method with default parameters. I'm still new to IL but it also shows that it clearly resolves to the method with default parameters.
This essentially hides the method signature method( string ) in child classes.
What exactly is happening here?
Is this a bug in C#? A bug in the compiler?
Are method calls higher up in the generation chain SUPPOSED to have precedence
over overwritten calls of their child?
Is there something I am just missing?
For the curious, the problem was resolved by using a delegate function
( ( Func<string, string> )base.method)("Test"); // prints out "Test"
**edit - The code now compiles if copy pasted
I have some problem, so I have a few global fields in class, for each I want to do the same code but I don't want to repeat code - just use one method for that. And there I want to send these global fields in argument of this method and as second argument I want to send value for this field.
I tried with object, generic type but I don't know how to do that. Here is example:
private void setName(String _name) {
if(isNull(_name)) {
this.name = "";
} else {
this.name = _name.toString();
}
}
And a few other methods use the same code but with other fields and argument and I want to do something like that:
private void setField(some_field, _value) {
if(isNull(_value)) {
this.some_field = "";
} else {
this.some_field = _value;
}
}
Could someone help?
For example I have 2 global fields:
String name, int age.
For them I need to use the same code (if) and I want do it in one method. In this case I have to use global field as argument and as second argument use correct value for this field so instead:
this.name = argument;
this.age=argument;
use: globa_field_argument = argument;
Example:
setField( this.name, "Test" );
setField( this.age, 5 );
First off I would probably declare your global fields as 'public static'.
for example:
public static int myNumber = 10;
public static String myString = "foo";
Secondly you should have to pass your fields as an argument since you can access them inside the method itself.
When you redefine the fields anywhere in your code you will do this:
this.myNumber = newNumber;
this.myString = newString;
This is my transformation function call:
<p><%# MyFunctions.getDocumentCategory(Eval("DocumentID"))%></p>
This is the function:
public static string getDocumentCategory(int documentID)
{
string category;
StringBuilder sb = new StringBuilder();
// Get document categories
var ds = CategoryInfoProvider.GetDocumentCategories(documentID, "CategoryEnabled = 1", null);
// Check whether exists at least one category
if (!DataHelper.DataSourceIsEmpty(ds))
{
// Loop thru all categories
foreach (DataRow dr in ds.Tables[0].Rows)
{
sb.Append(Convert.ToString(dr["CategoryDisplayName"]) + ",");
}
}
string content = sb.ToString();
category = content.Split(',')[0];
return category;
}
}
This is the error:
MyFunctions.getDocumentCategory(int) has some invalid arguments.
I've tried an alternate form of the function that accepts strings rather than ints but it throws the same error. I've verified that the Eval("DocumentID") works correctly when placed by itself. Any ideas?
Eval returns an object. You either need to convert it to an int, or change the function to accept an object, and convert that object to an int.
<p><%# MyFunctions.getDocumentCategory( Convert.ToInt32( Eval("DocumentID") ) )%></p>
OR
public static string getDocumentCategory(object document)
{
int documentID = Convert.ToInt32( document );
etc...
}
Thanks to Doozer for the nice explanation and example.
The second approach - to accept the object and make the conversion inside your custom function - may be better to keep the transformation code cleaner. The result is equal.
Just to add a little bit - you can use Kentico's ValidationHelper for conversions, for example:
transformation:
<%# MyFunctions.getDocumentCategory(Eval("DocumentID"))%>
code:
public static string getDocumentCategory(object docID)
{
int documentID = ValidationHelper.GetInteger(docID, 0); //0 is the default value
...