How to design a String class with MaxLength? - c#

I am planning to create my own string class, but it will have a max length provided.
Let's call it "lString".
I want to use "lString" just like a "string" class in my code. But I will be able to set a maxlength for it.
For example, this code should be built:
// 1- No maxlength provided, so the object will be created.
lString mylString1 = "0123456789";
// 2- maxlength provided, so it will be checked, and then created.
lString mylString2 = new lString("0123456789", 10);
// 3- This time only maxlength provided, so it will be a string object with maxLength.
lString mylString3 = new lString(20);
// At the end, I should be able to use it like a regular strings:
mylString3 = mylString1 + mylString2;
// Below should throw exception at RunTime, because it will be over 20)
mylString3 = mylString1 + mylString2 + mylString1 + mylString2;

Its fairly trivial to implement a basic string class which has implicit operators to and from a normal string:
public class LimitedString
{
private readonly string value;
private readonly long maxLength;
public LimitedString(string value, long maxLength = long.MaxValue)
{
if(value != null && value.Length > maxLength)
throw new InvalidOperationException("Value is longer than max length");
this.value = value;
this.maxLength = maxLength;
}
public override string ToString()
{
return value;
}
public override int GetHashCode()
{
return value.GetHashCode();
}
public override bool Equals(object o)
{
if(o is LimitedString)
return value == ((LimitedString)o).value;
return false;
}
public static implicit operator LimitedString(string str)
{
return new LimitedString(str);
}
public static implicit operator String(LimitedString ls)
{
return ls.value;
}
}
And then your first 2 cases work as expected:
LimitedString myString1 = "0123456789";
LimitedString myString2 = new LimitedString("0123456789", 10);
However, the only way you can make your third example work is like this:
LimitedString myString3 = new LimitedString(myString1 + myString2 + myString1 + myString2, 20); // Throws exception
As once you re-assign the value your specification of the max length is lost, so you cant do this:
LimitedString myString3 = new LimitedString(20); // This is fine - you could have a constructor that just takes the max length.
myString3 = myString1 + myString2 + myString1 + myString2; // but here you're re-assigning.
Live example: https://rextester.com/KVBBQT19360

Related

C# Generic variable changes if another same type generic changes

I've this class:
public class Pair<T, V>
{
public T A = default;
public V B = default;
public Pair()
{
A = default;
B = default;
}
public Pair(T a, V b)
{
A = a;
B = b;
}
public override bool Equals(object obj)
{
Pair<T, V> other = obj as Pair<T, V>;
return A.Equals(other.A) && B.Equals(other.B);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public override string ToString()
{
return "Pair: (" + A.ToString() + " , " + B.ToString() + ")";
}
}
And I have a class with two Pair variables:
public class FakeClass<T>
{
public T LastValue { get; protected set; } = default;
public T CurrentValue = default;
public void Execute()
{
LastValue = CurrentValue
}
}
public class FakeClassWithPair : FakeClass<Pair<int, int>> { }
Now if I execute this code:
FakeClassWithPair fake = new FakeClassWithPair();
fake.CurrentValue.A = 2;
fake.CurrentValue.B = 5;
fake.Execute();
fake.CurrentValue.A = 32;
fake.CurrentValue.B = 53;
In debugging Current Value and Last Value have the same value "32" and "53".
How can I avoid this?
Classes are reference types, so when you set LastValue = CurrentValue, that means both LastValue and CurrentValue refer to the same object.
If you want Value semantics you should declare your Pair as a struct. This means that an assignment does a copy of the value. Except ofc there already are a built in type for this: ValueTuple, with some special syntax that lets you declare types like (int A, int B). There is also a regular Tuple<T1, T2> if you do want a reference type.
Also note that I see no way for your example to run, fake.CurrentValue should be initialized to null and crash when accessed. Using a value type would also solve this, since they cannot be null.
So just change your example to FakeClassWithPair:FakeClass<(int A, int B)> and everything should work as you expect it to.
Definitely do not roll your own class for a pair if you want value semantics. Use the built-in value tuple, defined as (T a, V b).
Also if your content of FakeClass is cloneable then you should take advantage of that (for example arrays are cloneable). So the assignment in Execute() would check if the current value implements ICloneable and proceeds accordingly.
See this example code with output. The first example with fk variable is defined by FakeClass<(int,int)> and the second example with fa variable is defined by FakeClass<int[]>. Some fun code is added to display arrays as list of vales in ToString() in order to mimic the behavior of tuples with arrays.
public class FakeClass<T>
{
public T LastValue { get; protected set; } = default(T);
public T CurrentValue = default(T);
public void Execute()
{
if (CurrentValue is ICloneable cloneable)
{
LastValue = (T)cloneable.Clone();
}
else
{
LastValue = CurrentValue;
}
}
public override string ToString()
{
if (typeof(T).IsArray)
{
object[] last, current;
Array cv = CurrentValue as Array;
if (cv != null)
{
current = new object[cv.Length];
cv.CopyTo(current, 0);
}
else
{
current = new object[0];
}
Array lv = LastValue as Array;
if (lv != null)
{
last = new object[lv.Length];
lv.CopyTo(last, 0);
}
else
{
last = new object[0];
}
return $"Current=[{string.Join(",",current)}], Last=[{string.Join(",",last)}]";
}
return $"Current={CurrentValue}, Last={LastValue}";
}
}
class Program
{
static void Main(string[] args)
{
var fk = new FakeClass<(int a, int b)>();
fk.CurrentValue = (1, 2);
Console.WriteLine(fk);
// Current=(1, 2), Last=(0, 0)
fk.Execute();
fk.CurrentValue = (3, 4);
Console.WriteLine(fk);
// Current=(3, 4), Last=(1, 2)
var fa = new FakeClass<int[]>();
fa.CurrentValue = new int[] { 1, 2 };
Console.WriteLine(fa);
//Current=[1,2], Last=[]
fa.Execute();
fa.CurrentValue = new int[] { 3, 4 };
Console.WriteLine(fa);
//Current=[3,4], Last=[1,2]
}
}

When using GetPosition for ArrayAdapter, Object with Equal Fields Return UnEqual

I have created a dropdown in Android Xamarin from which I would like to auto select a dropdown value on page load. When the page is launched, it is passed a MyClass object with a Num value of 52. My dropdown has been passed an ArrayAdapter which has a list of MyClass objects, one of which has a Num value of 52. When I try to mySpinner.SetSelection(recommendedPosition); it is not working because myClassAdapter.GetPosition(recommendedValue) returns -1
I thought that the example in the following article (which shows me how to override the Equals and Hash functions of MyClass) would help me, but it still results in -1 being returned. It seems that these overridden functions are not being hit when I place a breakpoint on them.. but I understood that the GetPosition method calls IndexOf which should result in my overriden functions being called.
https://www.javaworld.com/article/3305792/comparing-java-objects-with-equals-and-hashcode.html
In this example, MyClass has one field of Num.. but my code has many more properties in MyClass, all of which are equal between recommendedValue and one of the items in listMyClass.
In InstantiateItem of my ViewPager I call:
var recommendedValue = new MyClass("52");
var List<MyClass> listMyClass = new List<MyClass> { new MyClass("52"), new MyClass("46") };
mySpinner = view.FindViewById<Spinner>(Resource.Id.mySpinner);
var myClassAdapter = new MyClassAdapter(view.Context, listMyClass);
mySpinner.Adapter = myClassAdapter;
//*
// I need the following to not return -1
//*
var recommendedPosition = myClassAdapter.GetPosition((MyClass)recommendedValue);
MyClass.cs
public class MyClass: Java.Lang.Object
{
private string Num { get; set; } = "";
public MyClass() {}
public MyClass(int? num)
{
Num = String.IsNullOrEmpty(num) ? "" : num;
}
public string GetNum()
{
return Num;
}
public override bool Equals(object other)
{
return Equals(other as MyClass);
}
public bool Equals(MyClass otherItem)
{
if (otherItem == null)
{
return false;
}
return otherItem.Num == Num;
}
public override int GetHashCode()
{
int hash = 19;
hash = hash * 31 + (Num == null ? 0 : Num.GetHashCode());
return hash;
}
}
Maybe you could consider not using GetPosition method,you could directly get the position like this :
var recommendedValue = new MyClass("52");
var List<MyClass> listMyClass = new List<MyClass> { new MyClass("52"), new MyClass("46") };
var recommendedPosition = listMyClass.IndexOf(recommendedValue);
or you could define a GetSelectPosition(MyClass myClass) in your MyClassAdapter :
class MyClassAdapter: ArrayAdapter<MyClass >
{
public Context context;
public List<MyClass> list;
...
public int GetSelectPosition(MyClass myClass)
{
return list.IndexOf(myClass);
}
}
then you could call like :
var recommendedPosition = myClassAdapter.GetSelectPosition(recommendedValue);

How to create a linq extension method with Func<>?

I've created extension methods that can be used like this:
string returnValue = numbers.At(separator, index).Slice();
But I want to create like this:
string returnValue = numbers.At(s => '.').Slice();
Here's the other code.
public class StringParameters
{
public string Text { get; set; }
public int Position { get; set; }
public StringParameters(string text, int position)
{
this.Text = text;
this.Position = position;
}
}
public static StringParameters At(this string text, char c)
{
int index = text.IndexOf(c);
if (index > 0)
{
int index2 = text.IndexOf(c, index + 1);
if (index2 > index)
{
text = text.Substring(index2, text.Length - index2);
}
return new StringParameters(text, index2 + 1);
}
return new StringParameters(null, -1);
}
public static string Slice(this StringParameters parameters)
{
return parameters.Text.Substring(parameters.Position);
}
Edit: I've edited the code and replaced ... with "something here". I do not still get the full idea what it should be there. My expectation is that the method should be more useful by this.
Edit 2: I have now an idea what I want to create with my code. I want to be able to make something like this:
string returnValue = numbers.At(s, i => GetStringParameter()).Slice();
Edit 3: I've edited the code a little bit. It will probably be more clearer now of what I want to achieve.
Edit 4: Corrected a mistake in the code above.
It is not clear for me what are you trying to achieve (start parameter, which you want to replace by function, is not used anywhere in At function), but here is an example extension function with Func<> parameter:
public static StringParameters At(this string text, char c, Func<int> startFunc)
{
int start = startFunc();
int index = text.IndexOf(c);
if (index > 0)
{
int index2 = text.IndexOf(c, index + 1);
if (index2 > index)
{
text = text.Substring(0, text.Length - index2);
}
return new StringParameters(text, index2 + 1);
}
return new StringParameters(null, -1);
}
Usage:
string returnValue = numbers.At(s, () => GetStartIndex()).Slice();
You don't need i => here until you have an argument that you will pass to the Func<> inside At function.
When you call int start = startFunc();, the function you passed as the parameter to At (GetStartIndex() in my example) will be called and its return value will be set to start variable.
I think you want
string returnValue = numbers.At(s, i => GetStringParameter()).Slice();
with the Slice extension method having a signature:
public static string Slice(this StringParameters parameters)
i.e. you want
StringParameters stringParameters = numbers.At(s, i => GetStringParameter());
string returnValue = stringParameters.Slice();
It sounds like you need an overload of your extension method, At, to have a signature like:
public static StringParameters At(this string text, S s, Func<T, U> func)
Where S is the type of the s you're passing in, T is the input to your Func, and U is the output type of the Func.
In the At method, you use your Func like you'd call a method, e.g.
Func<int, string> func = (int)i => i.ToString();
string s = func(123); // s == "123"
I have finally found the solution with the help of Aleksey Shubin and others. The final code looks like this:
public static class Linq
{
public class StringParameters
{
public string Text { get; set; }
public int Position { get; set; }
public StringParameters(string text, int position)
{
this.Text = text;
this.Position = position;
}
}
public static StringParameters At(this string text, Func<char> func)
{
char c = func();
int index = text.IndexOf(c);
if (index > 0)
{
int index2 = text.IndexOf(c, index + 1);
if (index2 > index)
{
text = text.Substring(index2, text.Length - index2);
}
return new StringParameters(text, index2 + 1);
}
return new StringParameters(null, -1);
}
public static string Cut(this StringParameters parameters)
{
return parameters.Text.Substring(parameters.Position);
}
}
This can be used like this:
string returnValue = "132.465..646.656.45".At(() => '.').Cut();
This returns the value of 6.45. It should return the value of 656.45 or probably 132.465, but this is pretty easy. Thanks everyone for your help.

Converting String to Int without converting the variable itself

I want to have a string, which I then want to pass to 2 variables.
One is Int, the other is string.
So normally I could do:
string1 = string2;
int1 = Convert.ToInt32(string2);
But I wonder if it's possible to do it in another approach,
I want to convert the string to Int just as it reaches the int1 variable; O don't want to convert the actually string2 to Int.
So basically like the topic says:
string1 = int1(convert to int) = string2
I am not sure if this is possible at all, hopefully it is.
Magic.
MagicInt x = 123;
string s = x;
int i = x;
Console.WriteLine("s is " + s);
Console.WriteLine("i is " + i);
public struct MagicInt
{
public MagicInt(int value)
{
_value = value;
}
public MagicInt(string value)
{
_value = int.Parse(value);
}
int _value;
public static implicit operator int(MagicInt value)
{
return value._value;
}
public static implicit operator string(MagicInt value)
{
return value._value.ToString();
}
public static implicit operator MagicInt(int value)
{
return new MagicInt(value);
}
public static implicit operator MagicInt(string value)
{
return new MagicInt(value);
}
}

Controlling the overflow in c#

I want to have a number (let's say i) whose range is between 0 to 26 so that when the number is 26 and it is incremented by 1 (say i++) the value returns to 0 (i.e. the value is circular).
Is there such a thing in c#? What is it called? If not then how would I implement this in code (overloaded operators are accepted).
Make a property that limits the value:
private int _value;
public int Value {
get { return _value; }
set { _value = value % 27; }
}
Now when you increase the property the setter will limit the value.
Example:
Value = 25;
Value++; // Value is now 26
Value++; // Value is now 0
Value++; // Value is now 1
You can try this:
int result = number % 27;
Use modulus operator (%)
var x = 0;
x = (x+1) % 27;
if you want it to go 0,1,2,3, ..... 24,25,26, 0, 1, 2, 3, ...
use modulus 27
I don't know of any sort of 'boundaries' or rules, you can "set" for an int in the way you want. I'd suggest creating an if statement, or two, to control it. `
if( i <= 26 & i >= 0)
{ ..do something..}
else i = 0;
Something like this should accomplish what you ask:
class CircularInt
{
public int value;
public static CircularInt operator ++(CircularInt c)
{
if (c.value >= 26)
c.value = 0;
else
c.value++;
return c;
}
}
Then use it:
CircularInt cInt = new CircularInt();
cInt++;
Console.WriteLine(cInt.value);
Another option is to define your own immutable type.
public struct Value27
{
private readonly int val;
private readonly bool isDef;
private Value27(int value)
{
while (value < 0) value += 27;
val = value % 27;
isDef = true;
}
public static Value27 Make(int value)
{ return new Value27(value); }
public bool HasValue { get { return isDef; } }
public int Value { get { return val; } }
public static Value27 operator +(Value27 curValue)
{ return Make(curValue.Value + 1); }
public static Value27 operator -(Value27 curValue)
{ return Make(curValue.Value + 26); }
public static implicit operator Value27(int bValue)
{ return Make(bValue); }
public static implicit operator int (Value27 value)
{ return value.Value; }
}

Categories