Solved

C# inheritance

Posted on 2014-09-08
9
186 Views
Last Modified: 2014-09-19
I am new to C# and .NET, and am having trouble understanding how a piece of code is working. My goal is to learn inheritance.

In the class below, on line 9, I am calling the PositiveDecimalRule(). When running in debugger, I am seeing that it skips IsDataTypeSupported method, and only executes RunValidationOnValue method. Why is this happening, and what is calling the RunValidationOnValue method to begin with?

I am reading a book on C#, and from my understanding, inheritance works like this: When PositiveDecimalRule() is called on line 9, a new object is created on the heap, and the default constructor for that class is called. However, because the PositiveDecimalRule is inheriting from ValidationRuleBase, the first constructor to run would be ValidationRuleBase's constructors. Once its constructors are done, the default constructor for PositiveDecimalRule class executes next. Since a constructor is not provided, the compiler will provide a default one automatically.

What happens next? How are the PositiveDecimalRule class' methods called? I don't see anything calling them, yet somehow RunValidationOnValue method executes/runs, but IsDataTypeSupported doesn't seem to run.

TestReport.cs
public class TestReport : I1ActiveReport
{
	...
	protected override void DoPrepareReport(Project.Reports.Report report, ReportParameter sourceParameter)
	{
		...
		
		ReportParameter costOfFunds = ReportParameter.NewParameter("CostOfFunds", "Cost of Funds", 6, ReportParameterType.Decimal, 1, 1, false);
		costOfFunds.ParameterValues.Rules.Add(new PositiveDecimalRule());
		report.Parameters.Add(costOfFunds);
		
		...
	}
}

public class PositiveDecimalRule : ValidationRuleBase
{
	public override bool IsDataTypeSupported(RuleDataType ruleDataType)
	{
		if (ruleDataType is DecimalCollection)
			return true;
		return false;
	}
	
	protected override ValidationResultBase RunValidationOnValue(RuleDataType ruleDataType,
																 string friendlyFieldName,
																 RuleSettings settings)
	{
		DecimalCollection list = ruleDataType as DecimalCollection;
		if( list == null || list.Count == 0)
			return null;
			
		foreach(Decimal value in list)
		{
			...
			return new ValidationResult(friendlyFieldName, message, ruleDataType, ValidationResultSeverity.Error);
		}
		
		return null;
	}
}

Open in new window


The code below shows the ValidationRuleBase abstract class.
ValidationRuleBase.cs
public abstract class ValidationRuleBase : IShallowCopy, IRuleOccurence
{
	public readonly ValidationRuleCategories RuleCategory;
	
	protected ValidationRuleBase()
		: this(ValidationRuleCategories.CustomRules)
	{ }

	protected ValidationRuleBase(ValidationRuleCategories category)
	{
		RuleCategory = category;
	}
	
	public abstract bool IsDataTypeSupported(RuleDataType ruleDataType);	
	...	
	protected abstract ValidationResultBase RunValidationOnValue(RuleDataType ruleDataType, string friendlyFieldName, RuleSettings settings);
	...
}

Open in new window

0
Comment
Question by:pzozulka
  • 3
  • 3
  • 3
9 Comments
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 40310506
>>inheritance works like this: ...
Nope, it doesn't.

Roughly said.  If you have a class X with various methods etc.  Now if you have a class Y which inherits from X then objects of class Y have the methods that Y has AND the methods that X has.  The other way round does not work - objects of class X have nothing to do with the methods that class Y has.

eg. in pseudo code
class X
{
  public foo
}

class Y : X
{
  public bar
}

...

X x = new X;
Y y = new Y;
x.Foo   //OK
y.Bar   //OK
y.Foo  //OK - because it is a method belonging to X
x.Bar  //FAIL, X has no idea what the method Bar is
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 40310514
There are special cases such as static methods/classes.  The general behaviour is as follows:

Constructors are called when you create an instance of an object eg.  Y y = new Y, that will call constructors for Y and for X.  
Calling the method in an object does not create a new instance of that object eg. y.Bar does not call any constructor.
0
 
LVL 8

Author Comment

by:pzozulka
ID: 40310558
When PositiveDecimalRule() is called on line 9, a new object is created on the heap
I see what through you off, I should not have put the parenthesis after PositiveDecimalRule because it's not a method, it's a class. Aside from that typo, I think I got the rest of that correct: >>inheritance works like this...

Is there another part of that paragraph that does not agree with what you said?

Aside from this, I'm still not sure how RunValidationOnValue() is being called. Yet in the debugger I can see it running.
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 40310640
...and the default constructor for that class is called. However, because the PositiveDecimalRule is inheriting from ValidationRuleBase, the first constructor to run would be ValidationRuleBase's constructors.
That's easy enough to confirm, right? Just write some throw-away code:

e.g.

using System;

namespace ConsoleApplication20
{
    class Program
    {
        static void Main(string[] args)
        {
            DerivedClass d = new DerivedClass();

            Console.ReadKey();
        }
    }

    class BaseClass
    {
        public BaseClass()
        {
            Console.WriteLine("In BaseClass constructor");
        }
    }

    class DerivedClass : BaseClass
    {
        public DerivedClass() : base()
        {
            Console.WriteLine("In DerivedClass constructor");
        }
    }
}

Open in new window


Jon Skeet has a good reference on this topic.

Are you certain there is nothing in ValidationRuleBase that is executing the method? abstract classes can still have methods which themselves are not abstract.
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 8

Author Comment

by:pzozulka
ID: 40310804
You are right, I found a a method in ValidationRuleBase that calls RunValidationOnValue().

ValidationRuleBase.cs
public virtual ValidationResultBase ValidateValue(RuleDataType ruleDataType, string friendlyFieldName, RuleSettings settings, bool force)
{
	ValidationResultBase result;
	
	result = RunValidationOnValue(ruleDataType, friendlyFieldName, settings);
	
	...
	
	return result;
	
}

Open in new window

How does it know to go to the RunValidationOnValue() method inside my TestReport.cs? Interestingly enough, in Visual Studio, if you right-click on method RunValidationOnValue() above, and select Go To Definition, it takes you to the definition inside of ValidationRuleBase.cs. But, during execution, it jumps to my overriding method in TestReport.cs.  I mean I get that I am overriding that method in TestReport.cs, but there are many other classes in this project that override this method as well. How does it know to jump to mine? I'm really confused by the order of execution.
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 40311362
>>How does it know to jump to mine?

I don't know the exact details (and this comment is based a bit more on C++, treat with caution) and this is a very superficial description.  If you need an accurate technical description I have no doubt you could find a text book devoting a chapter or two to the topic.
When the compiler constructs an object in code it doesn't use text to identify methods during code execution, it uses an address in memory.  In the class definition the compiler 'knows' that the first method is x bytes and the second is a further x bytes along and so on.  So to run a method in an object it will use this information to find where the method is in the memory assigned to the object, then run the method at that address.
To identify the method during compilation (not execution) to run the compiler requires both what type of object is it and what you have named the method.  Then it can determine the memory offset that will be required for when the code executes.  In other words the name of a method is for your benefit.  

Exactly what is going on with your Go To Definition that you describe above I don't understand.
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 40311823
How does it know to go to the RunValidationOnValue() method inside my TestReport.cs?
Because the method is declared as abstract in the base class. abstract methods (and properties) cannot have a method body. They must be overridden in a derived class. As you've written the code, there is nothing to execute in the base  RunValidationOnValue method. Really, it's more of a placeholder to say, "I expect that a derived class will provide this implementation."

When trying to figure out which implementation of a method will be invoked, you have to look at the type of object you created. It is invalid to say something like:

BaseClass b = new BaseClass();

...where BaseClass is an abstract class. Creating a derived class is no problem, though (provided it is not abstract itself):

DerivedClass d = new DerivedClass();

Even though you cannot create an instance of an abstract class, you can use a variable of that type to point to a concrete instance:

BaseClass b = new DerivedClass();

This is valid because DerivedClass inherits from BaseClass (as I defined earlier above). So if I say:

b.RunValidationOnValue();

...I will run the implementation of RunValidationOnValue found in the derived class because that is the type of object I created just above. If I had a second class:

class DerivedClass2 : BaseClass
{
    public override void RunValidationOnValue()
    {
        Console.WriteLine("In second derived RunValidationOnValue");
    }
}

Open in new window


...and I assigned an instance to that same variable:

b = new DerivedClass2();

...then DerivedClass2's implementation of RunValidationOnValue would be executed if I called the method:

b.RunValidationOnValue();

Interestingly enough, in Visual Studio, if you right-click on method RunValidationOnValue() above, and select Go To Definition, it takes you to the definition inside of ValidationRuleBase.cs.
This is expected behavior. You are inside of the base class when you click "Go to definition." That is where the definition, not the implementation of RunValidationOnValue is. Inside of your derived class, you have both a definition and an implementation of RunValidationOnValue. If you were to right-click the method in the derived class, it would take you to the derived class' definition of RunValidationOnValue.
0
 
LVL 8

Author Comment

by:pzozulka
ID: 40312338
kaufmed: I completely understand that if you call b.RunValidationOnValue(), RunValidationOnValue would be executed in DerivedClass2's implementation. However, RunValidationOnValue is not being called that way (using the dot operator of an object). RunValidationOnValue is being called from within the base class's ValidateValue method. See below:

Base Class ValidationRuleBase.cs
public abstract class ValidationRuleBase : IShallowCopy, IRuleOccurence
{
	public abstract bool IsDataTypeSupported(RuleDataType ruleDataType);
	protected abstract ValidationResultBase RunValidationOnValue(RuleDataType ruleDataType, string friendlyFieldName, RuleSettings settings);
	
	public virtual ValidationResultBase ValidateValue(RuleDataType ruleDataType, string friendlyFieldName, RuleSettings settings, bool force)
	{
		ValidationResultBase result;
		
		result = RunValidationOnValue(ruleDataType, friendlyFieldName, settings);
	}
}

Open in new window

As you can see, RunValidationOnValue is being called from inside the ValidateValue method from within the same base class.
0
 
LVL 74

Accepted Solution

by:
käµfm³d   👽 earned 500 total points
ID: 40312467
However, RunValidationOnValue is not being called that way (using the dot operator of an object).
And it doesn't have to be. When you have an abstract method, the defining (base) class does not provide an implementation, a derived class does. Because the base class does not provide an implementation, it has to defer to a derived class. Even though you might have a base-class variable pointing to a derived instance, that doesn't change what the actual object in memory is:  it's still an instance of the derived class. So when the base class method calls the abstact method, it executes the derived class' implementation, because ultimately your dealing with a derived class, not a base class.

It's related to what Andy mentioned above: When you have inherited classes with virtual/abstract methods being invoked,  there is a virtual call that is made by the runtime that determines which particular implementation of that method to invoke. The base class doesn't know anything about the specific implementation details of the method that the derived class provides, but it knows that the derived class has that method because in order to inherit from the base class it must implement that method (because it is abstract in the base class). Because the thing that is actually in memory is a derived class instance, its version of the method is what is invoked.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now