I have a class named FloatPlugIn. I want user to be able to do things like
FloatPlugIn x = new FloatPlugIn();
x.Minimum = -100;
x.Maximum = 100;
float y = 123;
x = y;
That is why I decided to add implicit operator to my class
public static implicit operator FloatPlugIn(float p)
{
return new FloatPlugIn() { Default = p };
}
Problem is that implicit operator has to be static that is why during conversion new instance of my class is created. As a result I am loosing all the information that was located inside of "old" instance.
Is there a way to fix that? I want float value to be applied to existing instance, not to completely replace it.
I don't think you're understanding what conversion does - it's not casting - it must create a new instance. It only makes sense to make it non-static if it were only updating the existing instance.
I think it's better in this case if you either use x.Default = y; or if you create a constructor that takes the float like this:
// Constructor
public FloatPlugIn(float p)
{
Default = p;
}
Usage:
float y = 123;
FloatPlugIn x = new FloatPlugIn(y);
The semantics of the assignment operator requires that behavior. In fact:
The assignment operator (=) stores the value of its right-hand operand in the storage location, property, or indexer denoted by its left-hand operand and returns the value as its result. The operands must be of the same type (or the right-hand operand must be implicitly convertible to the type of the left-hand operand).
It is not the purpose of the implicit conversion operator to modify a destination value—note that there may not be any such destination value, such as in case you pass the value to a parameter of a method.
I want float value to be added to existing instance, not to completely replace it.
If you want an addition (in whatever specific sense that would mean in your case), consider overriding the addition + operator, which in turn has effect on the addition assignment += operator. However, you won't eliminate the creation of a new FloatPlugIn instance anyway.
Consider you'd have the following method in FloatPlugIn, which would modify an existing instance:
public void Add(float f)
{
// do whatever 'addition' means in your case
}
Then the + operator should work like this:
public static FloatPlugIn operator +(FloatPlugIn a, float b)
{
FloatPlugIn result = a.Clone(); // here Clone() denotes any custom method that creates a copy of that instance
result.Add(b);
return b;
}
In your code, the following would work then:
FloatPlugIn x = new FloatPlugIn();
x.Minimum = -100;
x.Maximum = 100;
float y = 123;
x += y; // a new instance is created, but the 'addition' logic is preserved
Also, the same will intuitively work in case of passing a value to a method call:
ProcessMyFloatPlugin(x + 123.0f);
You can see that it is a really good idea to create a new instance of FloatPlugIn as a result of an operator. Otherwise, an in-place modification of x would be, in fact, a nasty side-effect, completely unexpected by any other developer. Note that if performance (avoiding dynamic memory allocations) is a concern, consider using structs.
Related
Im trying to create a ufloat class/struct in c#. It's more of a challenge for me, but would help me control some values in code. After trying a couple of approaches, I finally have one that seems to work:
public struct ufloat
{
public float Value
{
get{ return value; }
set
{
if(value < 0)
{
this.value = 0;
}
else
{
this.value = Math.Abs(value);
}
}
}
}
The problem is, I want it to behave like a typical basic type:
ufloat n = 5;
n += 1;
After some thinking I tried to overload the '=' operator, but it is not possible. Now I am out of ideas. This is why I ask, how can you change this:
ufloat x; x.value = 1;
to this:
ufloat x = 0; x = 1;
?
(Sorry if I am losing something really easy, but I am a self-taught "programmer" and I am pretty new to c#. I learnt c++ at first, and going from lower to higher level isn't easy for me.)
You can't overload the = operator, but you can overload the + operator, and then the += operator (which I believe you meant instead of =+) will work in a reasonably obvious way. You'd also need to add an implicit conversion from float to your struct though.
I would strongly advise not making the struct mutable though - instead, let the + operator return a new value. That will make it behave like every other primitive type, and like most other structs. I'd also rename it to USingle to follow the normal .NET naming conventions (where Single is the CLR name for float). You can't add your own C# alias for a name like float is for Single though.
I suspect your type will want:
A constructor accepting a float
Conversions to and from float (note that normally implicit conversions shouldn't throw exceptions - you may want to ignore that, but I'm not sure...)
Overloads for the arithmetic operators (+, -, * and /)
Overrides of ToString, Equals and GetHashCode
Implementation of IComparable<USingle> and IEquatable<USingle>
You should think about what you want to happen if you add two values which are "large positive floats" together - is the intention that your new type is able to support larger positive values than float can, or is it just "float but always non-negative"?
You can not overload = operator but you may write implicit casts, for example this one is for casting an int:
public class ufloat
{
public float value { get; }
public ufloat(int val) { value = Math.Abs(val); }
public static implicit operator ufloat(int input)
{
return new ufloat(input);
}
}
Now if you assign an int value to it, it will implicitly be converted to ufloat:
ufloat x = -5;
I know that some people will suggest other ways of performing this same function and I am only interested in specifically accomplishing my goal. I already have working code that performs said task and just would like to understand more about writing my own powerful objects - thank you.
My goal:
int x = 100;
Base b = new Base(0, 3);
b = x; // Preserves my baseNum of 3 for conversions
Code:
public class Base
{
public int count = 0; // represents the count of current numerical value in base ten digit count : 3 -> could be read NEVER user changed
public int baseNum = 10; // conversion base subscript -> """""
public int represented; // represented base ten value of conversion (used for output NOT mathmatically friendly) -> should be read BUT never change by user
public int numerical = 0;
public int[] basearray; // should NOT be modified read only
public Base()
{
//count = 0; // setting numerical will run digit count
baseNum = 10;
numerical = 0;
}
public Base(int i)
{
baseNum = 10;
numerical = i;
}
public Base(int n, int b)
{
baseNum = b;
numerical = n;
}
public static implicit operator Base(int i)
{
// Help needed
}
public static implicit operator int(Base b)
{
int i = b.numerical;
return i;
}
}
I have excluded much of the irrelevant code. This object holds a numerical value but provides a digit by digit reference to a converted format (as we count in base ten this object converts into other base forms)
What I wish is to preserve the current baseNum member and only update the numerical value of my object when using assignment.
As implicit conversion is a static function as far as I know there is no way to access the instance that will be used when assignments are performed after int is casted into my object.
Is there any way to perform this assignment operation in the way I wish?
Again - I already have many methods that allow me to modify the numerical member of the instance.
I also know that I can simply define the baseNum again after assignment.
I only wish to find out if there is a way to possibly utilize my object in the way I am imagining.
You simply can't do that.
When you write b = x, things happen under the hood are:
take the value if x
invoke implicit operator Base(int i) on the value of x, a Base object is returned
assign the returned object to b
There is no conventional way you can access the original value of b in step 2, where the conversion happens.
Is there any way to perform this assignment operation in the way I wish?
No, there is not. Conversion operators, implicit or explicit, always return a new object. And in the case of your reference type, the value returned is a reference, and the assignment is to variable holding that reference, which does not in any way modify the object that variable previously referred to.
Furthermore, I would suggest you should not want to do this anyway. An assignment that only modifies the target partially would be very confusing to anyone reading the code. At first, maybe just confusing to people unfamiliar with the design, but eventually, once the code's been sitting there for awhile without any need to work on it, even people who were theoretically well-versed in the design will have trouble remembering that it does this.
Stick with what you already have, where modification of individual components of an object are expressed explicitly. This will keep the code expressive, simple, and easy to understand.
In the last line of Main(), I get an error for trying to do pointer stuff, but what I'm actually trying to do is invoke the multiplication operator I defined inside the Foo class. If that isn't the syntax for invoking the multiplication, what is?
namespace test
{
class Program
{
class Foo
{
int foo;
public Foo(int n)
{
foo = n;
}
public static object operator *(Foo a,Foo b)
{
return new Foo(a.foo * b.foo);
}
}
static void Main(string[] args)
{
Foo a = new Foo(2);
Foo b = new Foo(3);
a * b;
}
}
}
I'm sure it's something stupid, but I don't see it.
In C#, the only expressions that can be used as statements (i.e. expressions which you can evaluate and simply ignore the result of the evaluation) are:
assignments: a = b;
the most obvious valid statement, but even the assignment expression has a result value, which means you can write one-liners like if ((a = b) == c) doStuff(); - so you are still "not using" the result of the assignment expression when doing a plain assignment
method calls: doStuff();
even if doStuff returns a value, you can use it as a statement
if you call a.ToString(); without storing the string anywhere, compiler won't complain
increments/decrements: i++;, i--;
post/pre-increment result semantics are pretty much the same in all C-like languages, it doesn't matter if you use the result (as in var x = i++;) or not
awaiting on a method: await doAsyncStuff();
you can await on an async operation without having to consume the result (this is basically analogous to plain method calls)
new object expressions: new Foo();
even if you don't assign the newly instantiated object to anything, its constructor might do a number of things affecting the state of the program, as well as create static references to itself (otherwise it will just get collected)
So, since are not consuming the result of this operation (assigning it to a variable), C# compiler assumes you are trying to define a variable b of type a*:
static void Main(string[] args)
{
Foo a = new Foo(2);
Foo b = new Foo(3);
// this is seen by the compiler as "type* variable;"
a * b;
}
This is why it gives you several compiler errors, like:
a is a variable, but is being used as a type
pointers are only allowed in an unsafe context
If you used a + operator, it wouldn't have mentioned any pointers, it would have just complained that you weren't supposed to use the expression as a statement, so it would probably make it more obvious.
To resolve the error, assign the result of the expression to a variable:
// type of `result` is an object, btw
var result = a * b;
As a side note, it would be wiser that your operator * method returns a result of type Foo, instead of a plain object:
public static Foo operator *(Foo a, Foo b)
{
...
}
// type of `result` is now `Foo`, as it should be
Foo result = a * b;
Final suggestion would be that this concrete example is a good candidate for an immutable struct, instead of a class (similar to the Point struct, for example).
Why does the following crash with a NullReferenceException on the statement a.b.c = LazyInitBAndReturnValue(a);?
class A {
public B b;
}
class B {
public int c;
public int other, various, fields;
}
class Program {
private static int LazyInitBAndReturnValue(A a)
{
if (a.b == null)
a.b = new B();
return 42;
}
static void Main(string[] args)
{
A a = new A();
a.b.c = LazyInitBAndReturnValue(a);
a.b.other = LazyInitBAndReturnValue(a);
a.b.various = LazyInitBAndReturnValue(a);
a.b.fields = LazyInitBAndReturnValue(a);
}
}
Assignment expressions are evaluated from right to left, so by the time we are assigning to a.b.c, a.b should not be null. Oddly enough, when the debugger breaks on the exception, it too shows a.b as initialized to a non-null value.
This is detailed in Section 7.13.1 of the C# spec.
The run-time processing of a simple assignment of the form x = y
consists of the following steps:
If x is classified as a variable:
x is evaluated to produce the variable.
y is evaluated and, if required, converted to the type of x through an implicit conversion (Section 6.1).
If the variable given by x is an array element of a reference-type, a run-time check is performed to ensure that the value
computed for y is compatible with the array instance of which x is an
element. The check succeeds if y is null, or if an implicit reference
conversion (Section 6.1.4) exists from the actual type of the instance
referenced by y to the actual element type of the array instance
containing x. Otherwise, a System.ArrayTypeMismatchException is
thrown.
The value resulting from the evaluation and conversion of y is stored into the location given by the evaluation of x.
If x is classified as a property or indexer access:
The instance expression (if x is not static) and the argument list (if x is an indexer access) associated with x are evaluated, and the results are used in the subsequent set accessor invocation.
y is evaluated and, if required, converted to the type of x through an implicit conversion (Section 6.1).
The set accessor of x is invoked with the value computed for y as its value argument.
I think the bottom section (if x is classified as a property or indexer access) provides a hint, but perhaps a C# expert can clarify.
A set accessor is generated first, then y is evaluated (triggering your breakpoint), then the set accessor is invoked, which causes a null reference exception. If I had to guess, I'd say the accessor points to the old value of b, which was null. When you update b, it doesn't update the accessor that it already created.
I realize this doesn't answer your question, but allowing something outside of class A to initialize a member belonging to class A in this fashion seems to me to break encapsulation. If B needs to be initialized on first use the "owner" of B should be the one to do that.
class A
{
private B _b;
public B b
{
get
{
_b = _b ?? new B();
return _b;
}
}
}
Hello I want ot create my own class for Point.
So in some graphic statements I need to call the object of the point to send its X and Y.
I want to know how can I send what I want to that for Example:
myPoint PT = new myPoint(1,2);
myPoint PT2 = new myPoint(10,20);
e.Graphics.DrawLine(pen, PT1, PT2);
I want to return the PT1 and PT2 as regular Point How can I do that?
You can use implicit conversion or explicit conversion. I recommend you explicit conversion.
Add in you myPoint class:
public static explicit operator Point(myPoint myPointToConvert)
{
return new Point(myPointToConvert.???, myPointToConvert.???);
}
With explicit convert you have to specify how you convert it with explicit cast:
e.Graphics.DrawLine(pen, (Point)PT1, (Point)PT2);
It's a little bit longer than in implicit converson but avoid some possible unexpected behavior (because you know exactly what you do).
If you are absolutely sure that you want to do implicit conversion then, in the above operator, just replace explicit by... implicit!