Are there any indicators to deciding whether to use a parameter or member variable?
See below example:
open class BankAccount(val accountCode: String, val accountName: String,
var balance : Double = 0.0) {}
vs.
open class BankAccount(val accountCode: String, val accountName: String) {}
var balance : Double = 0.0
The only question you have to ask is "Is this something that should be set via the constructor?" If yes, then use a parameter. If not, use a property. By adding var you're still making the declaration a property, you're just also adding a shortcut to initialize it from the constructor.
If you're coming from a Java background, looking at the Java equivalent would be helpful. It would be something like this:
public class BankAccount {
private final String mAccountCode;
private final String mAccountName;
private double mBalance;
public BankAccount(String accountCode, String accountName, double balance) {
mAccountCode = accountCode;
mAccountName = accountName;
mBalance = balance;
}
public BankAccount(String accountCode, String accountName) {
this(accountCode, accountName, 0.0d)
}
public void setBalance(double balance) {
mBalance = balance;
}
public double getBalance() {
return mBalance;
}
}
vs.
public class BankAccount {
private final String mAccountCode;
private final String mAccountName;
private double mBalance = 0.0d;
public BankAccount(String accountCode, String accountName) {
mAccountCode = accountCode;
mAccountName = accountName;
}
public void setBalance(double balance) {
mBalance = balance;
}
public double getBalance() {
return mBalance;
}
}
Notice that you get a constructor argument for the balance field in the first case. In either case you can update the value with a method call to the setter.
For your second question, when you should and shouldn't use val or var, the answer is "Use var to make the parameter a writable property, use val to make it a read-only property, and use nothing if you just want constructor args.
Again, the Java equivalent of something like this:
open class Example(var writable : Int, val readable : Int, constructorArg : Int) {
// Could use constructor arg to init another property
private val someOtherProperty : Int = constructorArg
// Or in the init block (the Kotlin "constructor" body)
init {
// Or do something with constructArg in the constructor
}
}
Would be something like this:
public class Example {
private int mWritable;
private final int mReadable;
private final int mSomeOtherProperty;
public Example(int writable, int readable, int contructorArg) {
mWritable = writeable;
mReadable = readable;
// Could use constructor arg to init another property
mSometOtherProperty = constructorArg;
// Or do something with constructArg in the constructor
}
public int getWritable() {
return mWritable;
}
public void setWritable(int writable) {
mWritable = writable;
}
public int getReadable() {
return mReadable;
}
The var attribute makes a property that has both a setter and a getter so you can update it.
The val attribute makes a property that only has a getter so you can read it.
The arg with no keyword makes no property - instead it is passed to the constructor for you to use as needed. This is a trivialized example so it does nothing, but in reality you would use it to either initialize other properties or with an init block.
Again, assuming you're coming from a Java background, you can use Intellij to run view the Kotlin byte code, then convert that to Java to see what the differences in the language do.
Here's the first google hit that explains this:
https://medium.com/#mydogtom/tip-how-to-show-java-equivalent-for-kotlin-code-f7c81d76fa8
Hope that helps!
TLDR: Use a parameter if you need to parameterise.
In the first case, you will be able to start an account with a non-zero balance.
If that is a scenario you find useful, it makes sense to make the balance an (optional) parameter. Otherwise, a member variable is more appropriate.
Related
In my project, I have this special function that does needs to evaluate the following:
State -- represented by an enum -- and there are about 6 different states
Left Argument
Right Argument
Left and Right arguments are represented by strings, but their values can be the following:
"_" (a wildcard)
"1" (an integer string)
"abc" (a normal string)
So as you can see, to cover all every single possibility, there's about 2 * 3 * 6 = 36 different logics to evaluate and of course, using if-else in one giant function will not be feasible at all. I have encapsulated the above 3 input into an object that I'll pass to my function.
How would one try to use OOP to solve this. Would it make sense to have 6 different subclasses of the main State class with an evaluate() method, and then in their respective methods, I have if else statements to check:
if left & right arg are wildcards, do something
if left is number, right is string, do something else
Repeat for all the valid combinations in each State subclass
This feels like the right direction, but it also feels like theres alot of duplicate logic (for example check if both args are wildcards, or both strings etc.) for all 6 subclasses. Then my thought is to abstract it abit more and make another subclass:
For each state subclass, I have stateWithTwoWildCards, statewithTwoString etc.
But I feel like this is going way overboard and over-engineering and being "too" specific (I get that this technically adheres tightly to SOLID, especially SRP and OCP concepts). Any thoughts on this?
Possibly something like template method pattern can be useful in this case. I.e. you will encapsulate all the checking logic in the base State.evaluate method and create several methods which subclasses will override. Something along this lines:
class StateBase
def evaluate():
if(bothWildcards)
evalBothWildcards()
else if(bothStrings)
evalBothStrings()
else if ...
def evalBothWildcards():
...
def evalBothStrings():
...
Where evalBothWildcards, evalBothStrings, etc. will be overloaded in inheritors.
there's about 2 * 3 * 6 = 36 different logics to evaluate
We can apply divide and conquer technique.
you have 6 states. It is possible to use Chain of Responibility pattern here to choose appropriate state handler
when desired state handler is found, then we can apply desired function. The appropriate function can be considered as strategy. So it is a place where Strategy pattern can be applied.
we can separate strategies by appropriate states and put them in simple factory to get desired strategy by key.
This is what we will do. So let's see it more thoroughly.
Chain of responsibility pattern
If you have a lot if else statements, it is possible to use Chain of Responsibility pattern. As wiki says about Chain of Responsibility:
The chain-of-responsibility pattern is a behavioral design pattern
consisting of a source of command objects and a series of processing
objects. Each processing object contains logic that defines the
types of command objects that it can handle; the rest are passed to
the next processing object in the chain. A mechanism also exists for
adding new processing objects to the end of this chain
So let's dive in code. Let me show an example via C#.
So this is our Argument class which has Left and Right operands:
public class Arguments
{
public string Left { get; private set; }
public string Right { get; private set; }
public MyState MyState { get; private set; }
public MyKey MyKey => new MyKey(MyState, Left);
public Arguments(string left, string right, MyState myState)
{
Left = left;
Right = right;
MyState = myState;
}
}
And this is your 6 states:
public enum MyState
{
One, Two, Three, Four, Five, Six
}
This is start of Decorator pattern. This is an abstraction of StateHandler which defines behaviour to to set next handler:
public abstract class StateHandler
{
public abstract MyState State { get; }
private StateHandler _nextStateHandler;
public void SetSuccessor(StateHandler nextStateHandler)
{
_nextStateHandler = nextStateHandler;
}
public virtual IDifferentLogicStrategy Execute(Arguments arguments)
{
if (_nextStateHandler != null)
return _nextStateHandler.Execute(arguments);
return null;
}
}
and its concrete implementations of StateHandler:
public class OneStateHandler : StateHandler
{
public override MyState State => MyState.One;
public override IDifferentLogicStrategy Execute(Arguments arguments)
{
if (arguments.MyState == State)
return new StrategyStateFactory().GetInstanceByMyKey(arguments.MyKey);
return base.Execute(arguments);
}
}
public class TwoStateHandler : StateHandler
{
public override MyState State => MyState.Two;
public override IDifferentLogicStrategy Execute(Arguments arguments)
{
if (arguments.MyState == State)
return new StrategyStateFactory().GetInstanceByMyKey(arguments.MyKey);
return base.Execute(arguments);
}
}
and the third state handler looks like this:
public class ThreeStateHandler : StateHandler
{
public override MyState State => MyState.Three;
public override IDifferentLogicStrategy Execute(Arguments arguments)
{
if (arguments.MyState == State)
return new StrategyStateFactory().GetInstanceByMyKey(arguments.MyKey);
return base.Execute(arguments);
}
}
Strategy pattern
Let's pay attention to the following row of code:
return new StrategyStateFactory().GetInstanceByMyKey(arguments.MyKey);
The above code is an example of using Strategy pattern. We have different ways or strategies to handle
your cases. Let me show a code of strategies of evaluation of your expressions.
This is an abstraction of strategy:
public interface IDifferentLogicStrategy
{
string Evaluate(Arguments arguments);
}
And its concrete implementations:
public class StrategyWildCardStateOne : IDifferentLogicStrategy
{
public string Evaluate(Arguments arguments)
{
// your logic here to evaluate "_" (a wildcard)
return "StrategyWildCardStateOne";
}
}
public class StrategyIntegerStringStateOne : IDifferentLogicStrategy
{
public string Evaluate(Arguments arguments)
{
// your logic here to evaluate "1" (an integer string)
return "StrategyIntegerStringStateOne";
}
}
And the third strategy:
public class StrategyNormalStringStateOne : IDifferentLogicStrategy
{
public string Evaluate(Arguments arguments)
{
// your logic here to evaluate "abc" (a normal string)
return "StrategyNormalStringStateOne";
}
}
Simple factory
There is no pattern like simple factory. However, it is a place where we can get instances of strategies by key. So by doing this we avoided to use multiple if else statements to choose correct strategy.
So, we need a place where we can store strategies by state and argument value. At first, let's create MyKey struct. It will have help us to differentiate State and arguments:
public struct MyKey
{
public readonly MyState MyState { get; }
public readonly string ArgumentValue { get; } // your three cases: "_",
// an integer string, a normal string
public MyKey(MyState myState, string argumentValue)
{
MyState = myState;
ArgumentValue = argumentValue;
}
public override bool Equals([NotNullWhen(true)] object? obj)
{
return obj is MyKey mys
&& mys.MyState == MyState
&& mys.ArgumentValue == ArgumentValue;
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 23 + MyState.GetHashCode();
hash = hash * 23 + ArgumentValue.GetHashCode();
return hash;
}
}
}
and then we can create a simple factory:
public class StrategyStateFactory
{
private Dictionary<MyKey, IDifferentLogicStrategy>
_differentLogicStrategyByStateAndValue =
new Dictionary<MyKey, IDifferentLogicStrategy>()
{
{ new MyKey(MyState.One, "_"), new StrategyWildCardStateOne() },
{ new MyKey(MyState.One, "intString"),
new StrategyIntegerStringStateOne() },
{ new MyKey(MyState.One, "normalString"),
new StrategyNormalStringStateOne() }
};
public IDifferentLogicStrategy GetInstanceByMyKey(MyKey myKey)
{
return _differentLogicStrategyByStateAndValue[myKey];
}
}
So we've written our strategies and we've stored these strategies in simple factory StrategyStateFactory.
Then we need to check the above implementation:
StateHandler chain = new OneStateHandler();
StateHandler secondStateHandler = new TwoStateHandler();
StateHandler thirdStateHandler = new ThreeStateHandler();
chain.SetSuccessor(secondStateHandler);
secondStateHandler.SetSuccessor(thirdStateHandler);
Arguments arguments = new Arguments("_", "_", MyState.One);
IDifferentLogicStrategy differentLogicStrategy = chain.Execute(arguments);
string evaluatedResult =
differentLogicStrategy.Evaluate(arguments); // output: "StrategyWildCardStateOne"
I believe I gave basic idea how it can be done.
This might be a duplicate. But I cannot find a solution to my Problem.
I have a class
public class MyResponse implements Serializable {
private boolean isSuccess;
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
}
Getters and setters are generated by Eclipse.
In another class, I set the value to true, and write it as a JSON string.
System.out.println(new ObjectMapper().writeValueAsString(myResponse));
In JSON, the key is coming as {"success": true}.
I want the key as isSuccess itself. Is Jackson using the setter method while serializing? How do I make the key the field name itself?
This is a slightly late answer, but may be useful for anyone else coming to this page.
A simple solution to changing the name that Jackson will use for when serializing to JSON is to use the #JsonProperty annotation, so your example would become:
public class MyResponse implements Serializable {
private boolean isSuccess;
#JsonProperty(value="isSuccess")
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
}
This would then be serialised to JSON as {"isSuccess":true}, but has the advantage of not having to modify your getter method name.
Note that in this case you could also write the annotation as #JsonProperty("isSuccess") as it only has the single value element
I recently ran into this issue and this is what I found. Jackson will inspect any class that you pass to it for getters and setters, and use those methods for serialization and deserialization. What follows "get", "is" and "set" in those methods will be used as the key for the JSON field ("isValid" for getIsValid and setIsValid).
public class JacksonExample {
private boolean isValid = false;
public boolean getIsValid() {
return isValid;
}
public void setIsValid(boolean isValid) {
this.isValid = isValid;
}
}
Similarly "isSuccess" will become "success", unless renamed to "isIsSuccess" or "getIsSuccess"
Read more here: http://www.citrine.io/blog/2015/5/20/jackson-json-processor
Using both annotations below, forces the output JSON to include is_xxx:
#get:JsonProperty("is_something")
#param:JsonProperty("is_something")
When you are using Kotlin and data classes:
data class Dto(
#get:JsonProperty("isSuccess") val isSuccess: Boolean
)
You might need to add #param:JsonProperty("isSuccess") if you are going to deserialize JSON as well.
EDIT: If you are using swagger-annotations to generate documentation, the property will be marked as readOnly when using #get:JsonProperty. In order to solve this, you can do:
#JsonAutoDetect(isGetterVisibility = JsonAutoDetect.Visibility.NONE)
data class Dto(
#field:JsonProperty(value = "isSuccess") val isSuccess: Boolean
)
You can configure your ObjectMapper as follows:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
{
if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
&& method.getName().startsWith("is")) {
return method.getName();
}
return super.nameForGetterMethod(config, method, defaultName);
}
});
I didn't want to mess with some custom naming strategies, nor re-creating some accessors.
The less code, the happier I am.
This did the trick for us :
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
#JsonIgnoreProperties({"success", "deleted"}) // <- Prevents serialization duplicates
public class MyResponse {
private String id;
private #JsonProperty("isSuccess") boolean isSuccess; // <- Forces field name
private #JsonProperty("isDeleted") boolean isDeleted;
}
Building upon Utkarsh's answer..
Getter names minus get/is is used as the JSON name.
public class Example{
private String radcliffe;
public getHarryPotter(){
return radcliffe;
}
}
is stored as { "harryPotter" : "whateverYouGaveHere" }
For Deserialization, Jackson checks against both the setter and the field name.
For the Json String { "word1" : "example" }, both the below are valid.
public class Example{
private String word1;
public setword2( String pqr){
this.word1 = pqr;
}
}
public class Example2{
private String word2;
public setWord1(String pqr){
this.word2 = pqr ;
}
}
A more interesting question is which order Jackson considers for deserialization. If i try to deserialize { "word1" : "myName" } with
public class Example3{
private String word1;
private String word2;
public setWord1( String parameter){
this.word2 = parameter ;
}
}
I did not test the above case, but it would be interesting to see the values of word1 & word2 ...
Note: I used drastically different names to emphasize which fields are required to be same.
You can change primitive boolean to java.lang.Boolean (+ use #JsonPropery)
#JsonProperty("isA")
private Boolean isA = false;
public Boolean getA() {
return this.isA;
}
public void setA(Boolean a) {
this.isA = a;
}
Worked excellent for me.
If you are interested in handling 3rd party classes not under your control (like #edmundpie mentioned in a comment) then you add Mixin classes to your ObjectMapper where the property/field names should match the ones from your 3rd party class:
public class MyStack32270422 {
public static void main(String[] args) {
ObjectMapper om3rdParty = new ObjectMapper();
om3rdParty .addMixIn(My3rdPartyResponse.class, MixinMyResponse.class);
// add further mixins if required
String jsonString = om3rdParty.writeValueAsString(new My3rdPartyResponse());
System.out.println(jsonString);
}
}
class MixinMyResponse {
// add all jackson annotations here you want to be used when handling My3rdPartyResponse classes
#JsonProperty("isSuccess")
private boolean isSuccess;
}
class My3rdPartyResponse{
private boolean isSuccess = true;
// getter and setter here if desired
}
Basically you add all your Jackson annotations to your Mixin classes as if you would own the class. In my opinion quite a nice solution as you don't have to mess around with checking method names starting with "is.." and so on.
there is another method for this problem.
just define a new sub-class extends PropertyNamingStrategy and pass it to ObjectMapper instance.
here is a code snippet may be help more:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
String input = defaultName;
if(method.getName().startsWith("is")){
input = method.getName();
}
//copy from LowerCaseWithUnderscoresStrategy
if (input == null) return input; // garbage in, garbage out
int length = input.length();
StringBuilder result = new StringBuilder(length * 2);
int resultLength = 0;
boolean wasPrevTranslated = false;
for (int i = 0; i < length; i++)
{
char c = input.charAt(i);
if (i > 0 || c != '_') // skip first starting underscore
{
if (Character.isUpperCase(c))
{
if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_')
{
result.append('_');
resultLength++;
}
c = Character.toLowerCase(c);
wasPrevTranslated = true;
}
else
{
wasPrevTranslated = false;
}
result.append(c);
resultLength++;
}
}
return resultLength > 0 ? result.toString() : input;
}
});
The accepted answer won't work for my case.
In my case, the class is not owned by me. The problematic class comes from 3rd party dependencies, so I can't just add #JsonProperty annotation in it.
To solve it, inspired by #burak answer above, I created a custom PropertyNamingStrategy as follow:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
{
if (method.getParameterCount() == 1 &&
(method.getRawParameterType(0) == Boolean.class || method.getRawParameterType(0) == boolean.class) &&
method.getName().startsWith("set")) {
Class<?> containingClass = method.getDeclaringClass();
String potentialFieldName = "is" + method.getName().substring(3);
try {
containingClass.getDeclaredField(potentialFieldName);
return potentialFieldName;
} catch (NoSuchFieldException e) {
// do nothing and fall through
}
}
return super.nameForSetterMethod(config, method, defaultName);
}
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
{
if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
&& method.getName().startsWith("is")) {
Class<?> containingClass = method.getDeclaringClass();
String potentialFieldName = method.getName();
try {
containingClass.getDeclaredField(potentialFieldName);
return potentialFieldName;
} catch (NoSuchFieldException e) {
// do nothing and fall through
}
}
return super.nameForGetterMethod(config, method, defaultName);
}
});
Basically what this does is, before serializing and deserializing, it checks in the target/source class which property name is present in the class, whether it is isEnabled or enabled property.
Based on that, the mapper will serialize and deserialize to the property name that is exist.
So i have a class that makes an array list for me and i need to access it in another class through a constructor but i don't know what to put into the constructor because all my methods in that class are just for manipulating that list. im either getting a null pointer exception or a out of bounds exception. ive tried just leaving the constructor empty but that dosent seem to help. thanks in advance. i would show you code but my professor is very strict on academic dishonesty so i cant sorry if that makes it hard.
You are confusing the main question, with a potential solution.
Main Question:
I have a class ArrayListOwnerClass with an enclosed arraylist property or field.
How should another class ArrayListFriendClass access that property.
Potential Solution:
Should I pass the arraylist from ArrayListOwnerClass to ArrayListFriendClass,
in the ArrayListFriendClass constructor ?
It depends on what the second class does with the arraylist.
Instead of passing the list thru the constructor, you may add functions to read or change, as public, the elements of the hidden internal arraylist.
Note: You did not specify a programming language. I'll use C#, altought Java, C++, or similar O.O.P. could be used, instead.
public class ArrayListOwnerClass
{
protected int F_Length;
protected ArrayList F_List;
public ArrayListOwnerClass(int ALength)
{
this.F_Length = ALength;
this.F_List = new ArrayList(ALength);
// ...
} // ArrayListOwnerClass(...)
public int Length()
{
return this.F_Length;
} // int Length(...)
public object getAt(int AIndex)
{
return this.F_List[AIndex];
} // object getAt(...)
public void setAt(int AIndex, object AValue)
{
this.F_List[AIndex] = AValue;
} // void setAt(...)
public void DoOtherStuff()
{
// ...
} // void DoOtherStuff(...)
// ...
} // class ArrayListOwnerClass
public class ArrayListFriendClass
{
public void UseArrayList(ArrayListOwnerClass AListOwner)
{
bool CanContinue =
(AListOwner != null) && (AListOwner.Length() > 0);
if (CanContinue)
{
int AItem = AListOwner.getAt(5);
DoSomethingWith(Item);
} // if (CanContinue)
} // void UseArrayList(...)
public void AlsoDoesOtherStuff()
{
// ...
} // void AlsoDoesOtherStuff(...)
// ...
} // class ArrayListFriendClass
Note, that I could use an indexed property.
Let's say I have a simple class in Java that stores a time stamp:
public final class Timestamp {
private final long value;
public Timestamp(final long value) {
this.value = value;
}
public long getValue() {
return value;
}
}
That's immutable. But what if instead of getValue() I write a method called getProgress()?
public final class Timestamp {
private final long value;
public Timestamp(final long value) {
this.value = value;
}
public float getProgress() {
return (SomeExternalPlace.getTimestamp() - value) / SomeFloatConstant;
}
}
The object's state never changes, but the value from getProgress() does change over time.
Is the latter class considered immutable? Why or why not?
It is immutable, because its state (the value field) cannot change once an instance of Timestamp has been created. The timestamp represents a certain point in time, and that cannot be changed.
Data returned from the methods doesn't necessarily need to be always the same.
Additionally, Timestamp exhibits all the properties you'd expect from an immutable object (e.g., thread-safety).
Here's another "weird" example of immutability:
class LazyList<T>
{
private readonly T _head;
private LazyList<T> _tail;
private readonly Func<LazyList<T>> _tailDelegate;
private bool _created;
public LazyList(T head, Func<LazyList<T>> tailDelegate)
{
_head = head;
_tailDelegate = tailDelegate;
_created = false;
}
public T GetHead()
{
return _head;
}
public LazyList<T> GetTail()
{
if(! _created)
{
_tail = _tailDelegate();
_created = true;
}
return _tail;
}
}
As you can see, the _tail isn't really immutable - it's null when LazyList<T> is instantiated, and is assigned only when the client calls GetTail(). But that really doesn't matter. Once the tail is created, it doesn't change; and before that, the tail still "exists", it just hasn't been realized yet.
This is actually how Scala's immutable Streams are implemented.
below is an extract from a Step Definition class of my Specflow project.
In the first method public void WhenIExtractTheReferenceNumber() I can successfully extract the text from the application under test, and I have proved this using the Console.WriteLine();
I need to be able to use this text in other methods with in my class I.e. public void WhenIPrintNumber(); But I'm not sure how to do this!
I read about Get/Set but I could not get this working. So I'm thinking is it possible to make my var result global somehow, so that I can call it at anytime during the test?
namespace Application.Tests.StepDefinitions
{
[Binding]
public class AllSharedSteps
{
[When(#"I extract the reference number")]
public void WhenIExtractTheReferenceNumber()
{
Text textCaseReference = ActiveCase.CaseReferenceNumber;
Ranorex.Core.Element elem = textCaseReference;
var result = elem.GetAttributeValue("Text");
Console.WriteLine(result);
}
[When(#"I print number")]
public void WhenIPrintNumber()
{
Keyboard.Press(result);
}
}
}
Thanks in advance for any thoughts.
Here is the solution to my question. Now I can access my variable(s) from any methods within my class. I have also included code that I'm using to split my string and then use the first part of the string. In my case I need the numerical part of '12345 - some text':
namespace Application.Tests.StepDefinitions
{
[Binding]
public class AllSharedSteps
{
private string result;
public Array splitReference;
[When(#"I extract the case reference number")]
public void WhenIExtractTheCaseReferenceNumber()
{
Text textCaseReference = ActiveCase.CaseReferenceNumber;
Ranorex.Core.Element elem = textCaseReference;
result = elem.GetAttributeValue("Text").ToString();
splitReference = result.Split('-'); // example of string to be split '12345 - some text'
Console.WriteLine(splitReference.GetValue(0).ToString().Trim());
}
[When(#"I print number")]
public void WhenIPrintNumber()
{
Keyboard.Press(result); // prints full string
Keyboard.Press(splitReference.GetValue(0).ToString()); // prints first part of string i.e. in this case, a reference number
}
}
}
I hope this help somebody else :)