I'm referring to my snippet Inheriting the stack class
After looong loong searches and many tries and tests, I finally came up with a version that works as I wanted to.
Stacker can now handle any type of object, even with arethmetic methods in place. The virtual way as proposed by JOShealV would work as well, but then you had to derive from Stacker and do some overriding.
Still two questions though:
1-- How should I handle nullable value types?
2-- What could be returned by the arithmetic methods? Nothing like now, should I throw an exception?
Any suggestions more than welcome, thanks in advance. :)

//Here is my changed code for reference

namespace StackTest
{
    class Program
    {
        struct MyStruct
        {
            public int i;
            public int MyMet()
            {
                return 42;
            }
        }

        class Person 
        {
            public string Name;
            public int ID;
        }

        static void Main(string[] args)
        {
            Person P1 = new Person { Name = "Tom", ID = 123 };
            Person P2 = new Person { Name = "Mary", ID = 124 };
            Stacker<Person> SP = new Stacker<Person>();
            SP.Push(P1);
            SP.Push(P2);
            SP.ADD();//no more exception !!

            Stacker<double> SD = new Stacker<double>();
            SD.Push(2);
            SD.Push(4.0);
            SD.Push(3.0);
            SD.DUP();
            SD.MUL();
            Console.WriteLine("The square of 3 is {0}.", SD.Peek());
            SD.ADD();
            Console.WriteLine("The sum is {0}.", SD.Peek());

            Stacker<MyStruct> SStr = new Stacker<MyStruct>();
            MyStruct S1;
            MyStruct S2;
            S1.i = 123;
            S2.i = 456;
            SStr.Push(S1);
            SStr.Push(S2);
            Console.WriteLine("before {0}.", SStr.Peek().i);
            SStr.ADD(); //no more exception
            Console.WriteLine("The sum is {0}.", SStr.Peek().i);//just check everything is the same

            Console.ReadKey();
        }
    }
}

//==============================================================================

using System.Collections.Generic;
using System;
using Microsoft.CSharp.RuntimeBinder;

namespace StackTest
{
    class Stacker<T> : Stack<T> 
    {
        public Stacker()
        { }

        /// <summary>
        /// Check generic type if it is numeric
        /// for the arithmetic stack methods
        /// Notice the use of default here
        /// See:https://msdn.microsoft.com/en-us/library/xwth0h0d.aspx
        /// </summary>
        /// <returns></returns>
        bool IsNumeric()
        {           
            try
            {               
                dynamic temp = default(T);
                bool b = temp == 0;
                return b;
            }
            // Include Microsoft.CSharp in references
            // and using Microsoft.CSharp.RuntimeBinder
            catch (RuntimeBinderException)//handle stacks
            {
                return false;
            }
        }

        /// <summary>
        /// Duplicate top of stack: n -- nn
        /// </summary>
        public void DUP()
        {
            T v = this.Pop(); this.Push(v); this.Push(v);
        }

        /// <summary>
        /// Multiply(if possible) the two top items on the stack
        /// replace with the result
        /// </summary>
        public void MUL() 
        {
            if ((Count >= 2) && IsNumeric())
            {
                dynamic v1 = Pop();
                dynamic v2 = Pop();
                Push(v1 * v2);
            }
            else
            {
            }
        }

        /// <summary>
        /// Sum(if possible) the two top items on the stack
        /// replace with the result
        /// </summary>
        public void ADD()
        {           
            if ((Count >= 2) && IsNumeric())
            {
                dynamic v1 = Pop();                    
                dynamic v2 = Pop();
                Push(v1 + v2);
            }           
            else
            {
            }
        }

        /// <summary>
        /// Substract(if possible) the two top items on the stack
        /// replace with the result
        /// </summary>
        public void SUB()
        {
            if ((Count >= 2) && IsNumeric())
            {
                dynamic v1 = Pop();
                dynamic v2 = Pop();
                Push(v2 - v1);
            }
            else
            {
            }
        }

        /// <summary>
        /// Divide(if possible) the two top items on the stack
        /// replace with the result
        /// </summary>
        public void DIV()
        {
            if ((Count >= 2) && IsNumeric())
            {
                dynamic v1 = Pop();
                dynamic v2 = Pop();
                Push(v1 / v2);
            }
            else
            {
            }
        }

        /// <summary>
        /// Negate(if possible) the top item on the stack
        /// replace with the result
        /// </summary>
        public void NEG()
        {
            dynamic v1 = Pop();
            Push(-v1);
        }

        /// <summary>
        /// Rotate the 3 th item to the top of the stack: n1 n2 n3 -- n2 n3 n1
        /// </summary>
        public void ROT()
        {
            if (Count >= 3)
            {
                dynamic v3 = Pop();
                dynamic v2 = Pop();
                dynamic v1 = Pop();
                Push(v2);
                Push(v3);
                Push(v1);
            }
        }

        /// <summary>
        /// Remove top item
        /// </summary>
        public void DROP()
        {
            T v = Pop();
        }

        /// <summary>
        /// Swap the two topmost items on the stack:n1 n2 -- n2 n1
        /// </summary>
        public void SWAP()
        {
            if (Count >= 2)
            {
                T v1 = Pop();
                T v2 = Pop();
                Push(v1);
                Push(v2);
            }
        }

        /// <summary>
        /// Copy the second item and make it the topmost:n1 n2 -- n1 n2 n1
        /// </summary>
        public void OVER()
        {
            if (Count >= 2)
            {
                T v1 = Pop();
                T v2 = Pop();
                Push(v1);
                Push(v2);
                Push(v1);
            }
        }
    }
}

Recommended Answers

All 3 Replies

I remember just yesturday I was doing some research about how to hide or disable certain classes that might be inherited (again I am using virtual here). Never the less, while looking for solutions, I did see throwing exceptions as a possibility. From an OOP perspective, that might be considered the most appropriate. I personally am still trying to find the best solution. One possibilty is to set all the possible ones to hide/reveal as protected in the base class, and then in the inherited, reveal the ones I want with an override and public.

You could just make it so nothing happens, but I think both of us would agreed that's a really bad design.

Personally I think I would stick with the exception throwing. I mean think about basic .NET, if you try to perform some operation that accepts objects, but it can't handle it due to the typing, .NET will throw an exception at you.

There also is that one warning you can get in .NET that warns you an operation might not work ... like when trying to compare a string to an object (I think that's one that throws it). If you could figure out how to do that, it might work, but would be a long shot.

As for nulls, I'd say throw an exception. Again just like base .NET, if you try to do anything against a null, a lot of times you'll get an exception (or in the case of say an equals function, you get false). Anymore I pretty much have taught myself that when a null occurs it means ignore doing any logic with it, or throw an error because it shouldn't have been null (telling the dev you got a bug you need to fix).

Interestingly enough on that last point, in some of our older code we have this check that if a value is null, we simply return a blank string or 0 depending on the type. However, what I saw was a problem is it could mask an error. For instance one client we upgraded and the newer code if it found a null blew an error. I ended up uncovering a very old bug in the client's custom code that was causing it to operate incorrectly. No one ever found it, and no one ever caught the flaw in the navigation (not sure how but it happened). When I uncovered the bug it ended up bringing forth there was a flaw in the code that needed to be fixed because some data that should have been present wasn't

I don't know either, how I could throw in a right warning, so I just follow your oppinion which was already mine also.
Copied some code from here to make my InvalidArithmeticException class.
And filled in theneeded code in Stacker.
Here is an example:

/// <summary>
        /// Multiply(if possible) the two top items on the stack
        /// replace with the result
        /// </summary>
        public void MUL() 
        {
            if ((Count >= 2) && IsNumeric())
            {
                dynamic v1 = Pop();
                dynamic v2 = Pop();
                Push(v1 * v2);
            }
            else
            {
                string message = "You cannot directly multiply two structs or classes, or stack too small.";
                throw new InvalidArithmethicException(message);
            }
        }

It is now the responsability of the comsuming class to set up a try/catch to handle the exception.
Again short example:

Person P1 = new Person { Name = "Tom", ID = 123 };
            Person P2 = new Person { Name = "Mary", ID = 124 };
            Stacker<Person> SP = new Stacker<Person>();
            SP.Push(P1);
            SP.Push(P2);
            try
            {
                SP.ADD();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

I must also mention that the VS debugger is a very nice tool, which has helped enourmously during testing an trying.
And I also thank JOShealIV for the advice.
I'm gonna leave the stacks etc. for what they are. I've seen enough of them lately and continue my C# quest,. I saw a traffic sign over there, marked WPF.
Let's see what lies ahead ...

HAHAHA, looks good. Now let's see those Regex skills of yours.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.