Skip to main content

Virtual, Override, and Abstract methods ( C# Specification Part 8)

When an instance method declaration includes a virtual modifier, the method is said to be a virtual method. When no virtual modifier is present, the method is said to be a non-virtual method.

When a virtual method is invoked, the run-time type of the instance for which that invocation takes place determines the actual method implementation to invoke. In a nonvirtual method invocation, the compile-time type of the instance is the determining factor.

A virtual method can be overridden in a derived class. When an instance method declaration includes an override modifier, the method overrides an inherited virtual method with the same signature. Whereas a virtual method declaration introduces a new method, an override method declaration specializes an existing inherited virtual method by providing a new implementation of that method.

An abstract method is a virtual method with no implementation. An abstract method is declared with the abstract modifier and is permitted only in a class that is also declared abstract. An abstract method must be overridden in every non-abstract derived class.
The following example declares an abstract class, Expression, which represents an expression tree node, and three derived classes, Constant, VariableReference, and Operation, which implement expression tree nodes for constants, variable references, and arithmetic operations.

using System;
using System.Collections;
public abstract class Expression
{
      public abstract double Evaluate(Hashtable vars);
}
public class Constant: Expression
{
      double value;
      public Constant(double value) {
            this.value = value;
      }
      public override double Evaluate(Hashtable vars) {
            return value;
      }
}
public class VariableReference: Expression
{
      string name;
      public VariableReference(string name) {
            this.name = name;
      }
      public override double Evaluate(Hashtable vars) {
            object value = vars[name];
            if (value == null) {
                  throw new Exception("Unknown variable: " + name);
            }
            return Convert.ToDouble(value);
      }
}
public class Operation: Expression
{
      Expression left;
      char op;
      Expression right;
      public Operation(Expression left, char op, Expression right) {
            this.left = left;
            this.op = op;
            this.right = right;
      }
      public override double Evaluate(Hashtable vars) {
            double x = left.Evaluate(vars);
            double y = right.Evaluate(vars);
            switch (op) {
                  case '+': return x + y;
                  case '-': return x - y;
                  case '*': return x * y;
                  case '/': return x / y;
            }
            throw new Exception("Unknown operator");
      }
}
The previous four classes can be used to model arithmetic expressions. For example, using instances of these classes, the expression x + 3 can be represented as follows.

Expression e = new Operation(
      new VariableReference("x"),
      '+',
      new Constant(3));

The Evaluate method of an Expression instance is invoked to evaluate the given expression and produce a double value. The method takes as an argument a Hashtable that contains variable names (as keys of the entries) and values (as values of the entries). The Evaluate method is a virtual abstract method, meaning that non-abstract derived classes must override it to provide an actual implementation.

A Constant’s implementation of Evaluate simply returns the stored constant. A VariableReference’s implementation looks up the variable name in the hashtable and returns the resulting value. An Operation’s implementation first evaluates the left and right operands (by recursively invoking their Evaluate methods) and then performs the given arithmetic operation.

The following program uses the Expression classes to evaluate the expression x * (y + 2) for different values of x and y.
using System;
using System.Collections;
class Test
{
      static void Main() {
            Expression e = new Operation(
                  new VariableReference("x"),
                  '*',
                  new Operation(
                        new VariableReference("y"),
                        '+',
                        new Constant(2)
                  )
            );
            Hashtable vars = new Hashtable();
            vars["x"] = 3;
            vars["y"] = 5;
            Console.WriteLine(e.Evaluate(vars));            // Outputs "21"

            vars["x"] = 1.5;
            vars["y"] = 9;
            Console.WriteLine(e.Evaluate(vars));            // Outputs "16.5"
      }
}

Comments

Popular posts from this blog

gcAllowVeryLargeObjects Element

There are numerous new features coming with .NET 4.5 and here, on this blog, you can find several posts about it. But the feature we are goint to talk about today is very exciting, because we were waiting for it more than 10 years. Since .NET 1.0 the memory limit of .NET object is 2GB. This means you cannot for example create array which contains elements with more than 2GB in total. If try to create such array, you will get the OutOfMemoryException. Let’s see an example how to produce OutOfMemoryException. Before that Open Visual Studio 2012, and create C# Console Application, like picture below. First lets create simple struct with two double members like example below: 1 2 3 4 5 6 7 8 9 10 11 12 public struct ComplexNumber {      public double Re;      public double Im;      public ComplexNumber( double re, double im)      {          Re=re;          Im=im;      } } As we know this structure consumes about 16

Support for debugging lambda expressions with Visual Studio 2015

Anyone who uses LINQ (or lambdas in general) and the debugger will quickly discover the dreaded message “Expression cannot contain lambda expressions”. Lack of lambda support has been a limitation of the Visual Studio Debugger ever since Lambdas were added to C# and Visual Basic.  With visual studio 2015 Microsoft has added support for debugging lambda expressions. Let’s first look at an example, and then I’ll walk you through current limitations. Example To try this yourself, create a new C# Console app with this code: using System.Diagnostics; using System.Linq; class Program { static void Main() { float[] values = Enumerable.Range(0, 100).Select(i => (float)i / 10).ToArray(); Debugger.Break(); } } Then compile, start debugging, and add “values.Where(v => (int)v == 3).ToArray()” in the Watch window. You’ll be happy to see the same as what the screenshot above shows you. I am using Visual Studio 2015 Preview and it has some limitations.

How to allow a very large object in .net application?

Since .NET 1.0 the memory limit of .NET object is 2GB. This means you cannot for example create array which contains elements with more than 2GB in total. If try to create such array, you will get the OutOfMemoryException. Let’s see an example how to produce OutOfMemoryException. Before that Open Visual Studio, and create C# Console Application. Lets create simple struct with two double members like example below: public struct ComplexNumber { public double Re; public double Im; public ComplexNumber(double re, double im) { Re = re; Im = im; } } As we know this structure consumes about 16 bytes of memory. So if we want to create array of this type which consume more than 2GB we need to create array at least with 134217728 instances. So this sample program below creates 130000000 (about 1,97 GB) of array. int maxCount = 130000000; ComplexNumber[] arr = null; try { arr = new ComplexNumber[maxCount]; } catch (Exception ex) { Console.WriteLine(ex.Message); } So if we run t