|
I'm working on a program that needs to model polynomials. The program has a Number class, and an Integer class that derives from it. There is some polynomial behavior that applies to polynomials with any Number coefficients, and some, like getPsuedoRemainder(), that applies only to Integer coefficient polynomials. This seemed to me like a natural application of class inheritance. I tried a structure like this,
class Polynomial<T> where T : Number
{
List<T> Coefficients { get; }
public Polynomial(List<T> coefficients)
{
Coefficients = coefficients;
}
}
class IntegerPolynomial : Polynomial<Integer>
{
public IntegerPolynomial(List<Integer> coefficients) : base(coefficients)
{ }
}
with the operations that apply to both classes, like addition and multiplication, defined in Polynomial<t>* and the Integer-specific ones defined in IntegerPolynomial. However, I ran into trouble choosing appropriate return types for the operations defined in Polynomial<t>. For example, the sum of two Polynomial<number> objects needs to be either another Polynomial<number> object or something that is castable to one, and likewise for IntegerPolynomial objects. This is the case because I need to be able to, for example, add two IntegerPolynomials and call getPsuedoRemainder() on the result. In order for the Polynomial<number> case to work out correctly, as far as I can tell that leaves me the choice between the following two signatures:
public static Polynomial<T> operator +(Polynomial<T> a, Polynomial<T> b)
public static Polynomial<Number> operator +(Polynomial<T> a, Polynomial<T> b)
The latter obviously doesn't also make sense for the IntegerPolynomial case. The former almost does, in that it would return Polynomial<integer> objects, but I've found that it isn't legal to cast from Polynomial<integer> to IntegerPolynomial.
Is there a way to tweak this structure so that the types work out? Or is there a much different structure that would be more appropriate?
*The preview shows every type I have in angled brackets inline in paragraphs as lower-case even though I typed them all as upper-case, as in the code examples. If you see the discrepancy, note that it isn't meaningful.
modified 6-Jan-18 4:19am.
|
|
|
|
|
If IntegerPolynomial overloads the operator+ too, then the problem of them adding to a "less useful type" is solved. It can pass-through the implementation, it just has to convert back to an IntegerPolynomial in the end.
Which leads me to: you can cast them, just not by a "free" type change. A Polynomial<Integer> isn't an IntegerPolynomial so you can't take an instance of it and change the type, but you can add a conversion operator to IntegerPolynomial so that it can be created out of a Polynomial<Integer> (creating a new instance with the same contents). Though this requires that Polynomial<Integer> is not the base class of IntegerPolynomial, so it's a bit annoying. Basically it trades being able to convert "for free" and code-sharing for the ability to convert in any direction.
|
|
|
|
|
"It can pass-through the implementation, it just has to convert back to an IntegerPolynomial in the end." Having the IntegerPolynomial version call the Polynomial<t> version, then convert the result, right?
"Though this requires that Polynomial<integer> is not the base class of IntegerPolynomial, so it's a bit annoying." I had previously encountered the idea that it isn't legal to define a cast from a base class to a derived class - is that what you're referring to here? I'm not sure how or if I could have Polynomial<integer> not be the base class of IntegerPolynomial and still get the code reuse I want, but maybe I could define a method, rather than a cast, that does this conversion:
public IntegerPolynomial getIntegerPolynomial()
{
List<Integer> coefficients = new List<Integer>();
foreach (Number coefficient in Coefficients)
coefficients.Add((Integer)coefficient);
return new IntegerPolynomial(coefficients);
}
It's kind of gross because I would only ever call it from Polynomial<integer> objects, where the creation of a new List is redundant, but the conversion is necessary for it to count as valid code. Seems like it would work in a pinch though.
modified 6-Jan-18 5:21am.
|
|
|
|
|
Yes I don't really like it either.. Here's an other idea: abandon a class for integer polynomials, and just add new methods to the generic polynomial through extension methods. Unlike normal methods, extension methods get to choose a specific instantiation of a generic type to "belong to", like this:
static Polynomial<Integer> Foo(this Polynomial<Integer> x)
{
}
Which has its own set of problems, such as that extension methods have no access to private fields/methods.
|
|
|
|
|
I was completely unaware of this option. It might work like a charm.
|
|
|
|
|
It did indeed, and saved me from doing a zillion casts I thought I was going to have to do.
|
|
|
|
|
Alexander Kindel wrote: There is some polynomial behavior that applies to polynomials with any Number coefficients, and some, like getPsuedoRemainder(), that applies only to Integer coefficient polynomials
That description doesn't sound like inheritance at all.
Any time one attempts to push behavior, and only behavior into an inheritance hierarchy then one must realize that they are doing so not because it is represented of inheritance but rather because it is convenient.
And doing that a lot will likely lead to maintenance problems over time.
|
|
|
|
|
By all means let me know what the principled thing to do instead would be, though I do have a solution that seems to be working fine for the moment in the form of harold aptroot's extension method suggestion.
|
|
|
|
|
Depends on specifics but in general one looks to composition or helper classes. Or even taking a look at the architecture to see if the overall design is flawed.
|
|
|
|
|
I created a button, and then in its mouse click event handler (the button_Click method) I have actions to perform once the user clicks on that button.
The next day, I would like to modify the button_Click method, I find that this method is empty, it does not contain any code !!!! Bearing that the button works well and the actions are done as usual !!!
The event clicks on the button is related to the button_Click method, but this method is empty !! So I want to know how the actions are performed once I click onthe button ?
Thank you
|
|
|
|
|
There is some kind of action that results in the IDE making a duplicate method that is renamed with a "-1" at the end or something like that. You may have run into something where you inadvertently created a duplicate method and wrote the working code there. And then when you look at the method in your code it looks empty. That is because it is the other method where you wrote the code that is actually running. That has happened to me several times and it can be quite frustrating. Good Luck!
|
|
|
|
|
Go to the design view, highlight your button, and look at the Properties pane. Select "Events" - it's looks like a lightning bolt - and scroll down to Click.
Look at the method that is attached, and note what it is called.
Now open the drop down and look at the list of compatible methods.
Are there two with similar names?
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
A possibility: you have modified the Button Click EventHandler, but, somehow, whatever Project/Class contains your code has not been re-compiled.
What's the structure of your app: single project ? WinForms? Or ?
Unfortunately, this is not just speculation: it happens to me now using VS2017 WinForms when I am using multi-project solutions, multiple namespaces, etc.
For unknown reasons I have to rebuild every part of the solution ... sometimes more than once ... to have the changed code used at run-time.
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
|
|
|
|
|
That's usually a result of a glitch in the matrix: did you take the blue pill or the red pill this morning?
Also: clean your solution, close VS.
Manually check the file modification timestamps: just sorting in descending order should do.
Reopen VS, clean again, and rebuild all.
This has fixed it for me when I've had this problem before with 2010, 2013, and 2015 VS
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Hi Griff,
I took the green pill, the one with the creme de mental flavour ... from that hookah-puffing caterpiggle's VSOPR stock
I am already following your kind advice when I get so tired of repeating the clean-rebuild-build cycle that I'm desperate enough.
Sometimes I will remove references to the class project dll's used in a WinForm project, and then re-add them. Even though I have cleaned and built the code in the classes with no output warnings ... the main solution won't build and can show a variety of error type feedback.
For me these problems started with VS2015, and hav gotten worse in VS 2017 ... that may reflect a change in my programming practice to breaking out functional units with no UI into separate class projects ... for future re-use.
cheers, Bill
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
|
|
|
|
|
Hello. New to C# so experimenting. Previous language VBA, where I used Application.EnableEvents to turn event handling on and off. Realise that's pretty sledgehammer.
Discovered this, which has as yet unfamiliar syntax, but works:
kiloTextBox.TextChanged -= kiloTextBox_TextChanged;
What would I write if I was looping through an array of text boxes textBoxes [i] to turn all their event handlers on and off?
Can it be done that way?
Could someone explain the syntax?
Thanks for your time.
Pogoodill
|
|
|
|
|
It's exactly the same syntax: the "-=" removes a specific event handler from the chain of handlers for each event.
To explain that, assume you have a class with an Event:
public class MyClass
{
public event EventHandler TestEvent;
protected virtual void OnTestEvent(EventArgs e)
{
EventHandler eh = TestEvent;
if (eh != null)
{
eh(this, e);
}
}
public void Signal()
{
OnTestEvent(null);
}
} And that you create an instance, and attach two handlers to the event, and raise teh event:
void mc_TestEvent1(object sender, EventArgs e)
{
Console.WriteLine("Event handler 1");
}
void mc_TestEvent2(object sender, EventArgs e)
{
Console.WriteLine("Event handler 2");
}
private void MyButton_Click(object sender, EventArgs e)
{
MyClass mc = new MyClass();
mc.TestEvent += mc_TestEvent1;
mc.TestEvent += mc_TestEvent2;
mc.Signal();
} You will get this output:
Event handler 1
Event handler 2 Because event handlers are "chained" - all handlers attached to the event for that specific instance will get fired.
So this code:
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();
mc1.TestEvent += mc_TestEvent1;
mc2.TestEvent += mc_TestEvent2;
mc1.Signal(); Will only output one line:
Event handler 1 Because only one event handler is attached for each instance. To get the output
Event handler 1
Event handler 2 You would have to call Signal on both instances:
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();
mc1.TestEvent += mc_TestEvent1;
mc2.TestEvent += mc_TestEvent2;
mc1.Signal();
mc2.Signal(); the "-=" syntax removes an event handler:
MyClass mc = new MyClass();
mc.TestEvent += mc_TestEvent1;
mc.TestEvent += mc_TestEvent2;
Console.WriteLine("Two:");
mc.Signal();
mc.TestEvent -= mc_TestEvent1;
Console.WriteLine("One:");
mc.Signal();
Gives you:
Two:
Event handler 1
Event handler 2
One:
Event handler 2
So, if you have a collection of MyClass objects, you can remove the handler inside the loop using exactly the same syntax:
foreach (MyClass mc in myClassesCollection)
{
mc.TestEvent -= mc_TestEvent1;
}
Note that this doesn't "turn the events off" it just removes a specific handler method from the instance (which probably as far as you care, turns it off!)
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Thanks so much for the detailed explanation of the syntax. Very much appreciated. I understand most of it. However, as far as I can see, the example will work when each event handler is called the same, eg.
textBoxes[i].TextChanged-= anEventHandlerWithGenericName_TextChanged
but my event handlers are called different things, based on their objects' names:
kiloTextBox.TextChanged -= kiloTextBox_TextChanged
poundTextBox.TextChanged -= poundTextBox_TextChanged
stoneTextBox.TextChanged -= stoneTextBox_TextChanged
My naive, straw-clutching attempt was...
textBoxes[i].TextChanged-= textBoxes[i] + "_TextChanged"
... which obviously didn't work. How do I reference all of the event handlers using my looping variable [i]?
Thanks again for your time.
|
|
|
|
|
You can't specify wild cards for removing event handlers, and while it can be done, it gets complicated! Reflection is the answer here...
static void RemoveEvents(object o, string nameOfEvent)
{
FieldInfo fi = o.GetType().GetField(nameOfEvent, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
if (fi != null)
{
fi.SetValue(o, null);
}
}
private void MyButton_Click(object sender, EventArgs e)
{
MyClass mc = new MyClass();
mc.TestEvent += mc_TestEvent1;
mc.TestEvent += mc_TestEvent2;
Console.WriteLine("Two:");
mc.Signal();
RemoveEvents(mc, "TestEvent");
Console.WriteLine("None:");
mc.Signal();
}
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Thanks again! Plenty for me to chew on there. I've only been at it for a couple of weeks so will take a little time to sink in.
Really appreciate your help.
|
|
|
|
|
OriginalGriff has given you the "grand tour" of EventHandlers here; I hope I can add another perspective:
1. the "head 'em off at the pass" stratagem: if you don;t want the TextBoxes to raise the Event, consider setting their 'Enabled property to 'false, or their locked Property to 'true.
or ... if you want the user to enter edit text, but, not raise the event:
2. the sub-class stratagem: you inject an action into the instances of the sub-classed TextBox; whether that action is executed is controlled by a boolean flag
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace YourNameSpace
{
public partial class TextBoxEXEvents : TextBox
{
public TextBoxEXEvents()
{
InitializeComponent();
}
public Action<string, string> TextChangedAction { set; get; }
public bool IsTextChangedEnabled = true;
public TextBoxEXEvents(IContainer container)
{
container.Add(this);
InitializeComponent();
}
private void TextBoxEXEvents_TextChanged(object sender, EventArgs e)
{
if (IsTextChangedEnabled && TextChangedAction != null) TextChangedAction(this.Text, this.Name);
}
}
} Here's an example of how this can be used:
private List<TextBoxEXEvents> TBxExInUse;
private void TextChangedAction(string text, string name = "")
{
Console.WriteLine($"text: {text} in: {name}");
}
TBxExInUse = this.Controls.OfType<TextBoxEXEvents>().ToList();
foreach (var tbxex in TBxExInUse)
{
tbxex.TextChangedAction = TextChangedAction;
}
foreach (var tbxex in TBxExInUse)
{
tbxex.IsTextChangedEnabled = YourBooleanValue;
}
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
|
|
|
|
|
Sometimes, instead of "wiring" and "unwiring", it's easier just to test a "flag" in the "wired" event handler as to whether to "execute" or not.
All the text boxes can be wired to the same hander; you can test for which textbox in the handler via the sender object(s) and arguments.
(And improper "wiring" / unwiring can result in memory leaks; duplicate event firings).
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
I have a specific problem I've been trying to solve, and I think I have the right pieces - I'm just putting them together incorrectly. It might be more of a math question than a coding one.
So basically what I want to be able to do is find where "now" is within an arbitrary recurring time period (say, 43 minutes), given a known DateTime that this period recurred. So you have an anchor point, and from that anchor point, you know that every 43 minutes this period starts over, where is "now" in the current period?
I'm sure it involves division and/or modulo, and likely a subtraction using the anchor...so I've been toying with this code, but it isn't giving me the results I'm looking for:
using System;
public class Program
{
public static void Main()
{
TimeSpan interval = new TimeSpan(0, 43, 0);
DateTime anchor = new DateTime(2018, 1, 5, 7, 0, 49);
DateTime now = DateTime.Now;
TimeSpan left = new TimeSpan((now - anchor).Ticks % interval.Ticks);
Console.WriteLine(left);
}
}
Can someone tell me the piece I'm missing here? I'm not entirely sure what mathematical operations DateTime supports, or which ones I should be using in this instance.
Thanks.
|
|
|
|
|
Try it like this :
public static void Main()
{
TimeSpan interval = new TimeSpan(0, 43, 0);
DateTime anchor = new DateTime(2018, 1, 5, 7, 0, 49);
TimeSpan left = new TimeSpan((DateTime.Now - anchor).Ticks % interval.Ticks);
Console.WriteLine(left.toString);
}
... but realize that you get no repeating value - you have to restart it again and again to see new values ...
|
|
|
|
|
I think the confusion is due to the inclusion of "Ticks", when your basic unit is "minutes" (in this case).
Makes no sense to go "smaller" than your smallest sample rate.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|