Inheritance Problem. Can I do this?
-
Hi All. I have a StaffMember class in my app that is inherited by my data access layer to StaffMemberOracleUDT. My reasoning for this is that the OracleUDT version has the data access part needed to convert an Oracle object to something I can use and then I can just send back the StaffMember base to be used in the UI layer. The problem I'm having is that I need to access the properties in the base class (Name, ID etc) but I also need to over ride these in the inherited class as each property needs a special OracleObjectMappingAttribute added to it that cannot be added to the base as I would then need to reference the Data Access Layer in my UI layer which shouldn't really be done. Any help is greatly appreciated.
The FoZ
-
Hi All. I have a StaffMember class in my app that is inherited by my data access layer to StaffMemberOracleUDT. My reasoning for this is that the OracleUDT version has the data access part needed to convert an Oracle object to something I can use and then I can just send back the StaffMember base to be used in the UI layer. The problem I'm having is that I need to access the properties in the base class (Name, ID etc) but I also need to over ride these in the inherited class as each property needs a special OracleObjectMappingAttribute added to it that cannot be added to the base as I would then need to reference the Data Access Layer in my UI layer which shouldn't really be done. Any help is greatly appreciated.
The FoZ
The short answer is "yes". :) I think it's a slightly odd dependency pattern you're creating - your DALs will depend on the business layer - but it is possible. And you don't need to reference the DAL from the UI - just the business layer. In your business layer you'll have:
public class StaffMember
{
virtual public string Name { get; set; }
}and in the Oracle DAL
public class StaffMemberOracle : StaffMember
{
[SomeAttribute]
override public string Name { get; set; }
}You never actually "convert" between these two types: The derived class IS the base class plus something of it's own.
public StaffMember LoadStaffMember(int id)
{
// Returns instances of derives classes like StaffMemberOracle.
// Even though the declared return type is "StaffMember", if you
// return an instance of StaffMemberOracle, the attribute on the
// Name property is present.
switch (DB)
{
case "Oracle": return OracleDAL.LoadStaffMember(id);
case "MSSQL": return MssqlDAL.LoadStaffMember(id);
...
}
}Not that I'd do that! Rather than have a bunch of switches in every method in the business layer that uses the DAL, create an interface that all DALs implement. Then your code will be something like
public StaffMember LoadStaffMember(int id)
{
return CreateDAL().LoadStaffMember(id);
}public Something LoadSomething(int id)
{
return CreateDAL().LoadSomething(id);
}IDAL CreateDAL()
{
get
{
switch (DB)
{
case "O": return new OracleDAL();
case "MS": return new MsSqlDAL();
...
}
}
}HTH
-
The short answer is "yes". :) I think it's a slightly odd dependency pattern you're creating - your DALs will depend on the business layer - but it is possible. And you don't need to reference the DAL from the UI - just the business layer. In your business layer you'll have:
public class StaffMember
{
virtual public string Name { get; set; }
}and in the Oracle DAL
public class StaffMemberOracle : StaffMember
{
[SomeAttribute]
override public string Name { get; set; }
}You never actually "convert" between these two types: The derived class IS the base class plus something of it's own.
public StaffMember LoadStaffMember(int id)
{
// Returns instances of derives classes like StaffMemberOracle.
// Even though the declared return type is "StaffMember", if you
// return an instance of StaffMemberOracle, the attribute on the
// Name property is present.
switch (DB)
{
case "Oracle": return OracleDAL.LoadStaffMember(id);
case "MSSQL": return MssqlDAL.LoadStaffMember(id);
...
}
}Not that I'd do that! Rather than have a bunch of switches in every method in the business layer that uses the DAL, create an interface that all DALs implement. Then your code will be something like
public StaffMember LoadStaffMember(int id)
{
return CreateDAL().LoadStaffMember(id);
}public Something LoadSomething(int id)
{
return CreateDAL().LoadSomething(id);
}IDAL CreateDAL()
{
get
{
switch (DB)
{
case "O": return new OracleDAL();
case "MS": return new MsSqlDAL();
...
}
}
}HTH
Thanks for you reply but I am having a few problems. I have set it out like you have above but my properties have private members associated to them. If I have code in the get & set on the base I get an error in the inherited class "inherited.staffid.set cannot override inherited member base.StaffID.set because it is not marked virtual, abstract or overrride." My base class property is marked virtual and the inherited is marked override.
public class StaffMember
{
protected int staffID;virtual public int StaffID { get { return staffID; } set { staffID = value } }
}
public class StaffMemberOracle : StaffMember, INullable, IOracleCustomType
{
[OracleObjectMappingAttribute("STAFFID")]
override void int StaffID
{
get { return staffID; }
set { staffID = value }
}
}I think I may be going about this the wrong way. Cheers
The FoZ
-
Thanks for you reply but I am having a few problems. I have set it out like you have above but my properties have private members associated to them. If I have code in the get & set on the base I get an error in the inherited class "inherited.staffid.set cannot override inherited member base.StaffID.set because it is not marked virtual, abstract or overrride." My base class property is marked virtual and the inherited is marked override.
public class StaffMember
{
protected int staffID;virtual public int StaffID { get { return staffID; } set { staffID = value } }
}
public class StaffMemberOracle : StaffMember, INullable, IOracleCustomType
{
[OracleObjectMappingAttribute("STAFFID")]
override void int StaffID
{
get { return staffID; }
set { staffID = value }
}
}I think I may be going about this the wrong way. Cheers
The FoZ
override void int StaffID
should beoverride public int StaffID
. -
Thanks for you reply but I am having a few problems. I have set it out like you have above but my properties have private members associated to them. If I have code in the get & set on the base I get an error in the inherited class "inherited.staffid.set cannot override inherited member base.StaffID.set because it is not marked virtual, abstract or overrride." My base class property is marked virtual and the inherited is marked override.
public class StaffMember
{
protected int staffID;virtual public int StaffID { get { return staffID; } set { staffID = value } }
}
public class StaffMemberOracle : StaffMember, INullable, IOracleCustomType
{
[OracleObjectMappingAttribute("STAFFID")]
override void int StaffID
{
get { return staffID; }
set { staffID = value }
}
}I think I may be going about this the wrong way. Cheers
The FoZ
-
Sorry that was a typo! I think I have solved it. I need to use the new keyword
new public int StaffID
to declare a new version of the property. Intellisense seems to like it :) Thanks for your effortThe FoZ
No, you don't need "new". You need "override". The "new" keyword is for member *hiding*, not overriding. To understand why, you need to know about the difference between virtual and non-virtual members, also often described as "late-bound" and "early-bound" members. It's also helpful to understand the concepts of reference types and value types. A couple resources I dug up for you quickly (you may want to google for others if they don't work for you): Value Types vs Reference Types[^] Virtual Members vs Non-Virtual[^] Or google "polymorphism" and these other terms I've mentioned. In brief, virtual members work as follows: When a member is accessed, such as method Foo(), the implementation of that method is resolved ("bound") at run-time, based on the run-time (actual) type of the object. For non-virtual members, the implementation is resolved at compile time (when you compile), based on the declared type of the reference. For example: public class A { virtual public string Foo() { return "A.Foo()"; } } public class B : A { override public string Foo() { return "B.Foo()"; } } void test() { A obj = new A(); MessageBox.Show(obj.Foo()); // "A.Foo()" obj = new B(); // Now, "obj" is still of declared type "A", but run-time type "B". MessageBox.Show(obj.Foo()); // "B.Foo()" } If instead you declared A.Foo without the virtual keyword and used new to hide this method in B, the second call to "obj.Foo" would still resolve to A.Foo, because obj is of declared type A.
-
No, you don't need "new". You need "override". The "new" keyword is for member *hiding*, not overriding. To understand why, you need to know about the difference between virtual and non-virtual members, also often described as "late-bound" and "early-bound" members. It's also helpful to understand the concepts of reference types and value types. A couple resources I dug up for you quickly (you may want to google for others if they don't work for you): Value Types vs Reference Types[^] Virtual Members vs Non-Virtual[^] Or google "polymorphism" and these other terms I've mentioned. In brief, virtual members work as follows: When a member is accessed, such as method Foo(), the implementation of that method is resolved ("bound") at run-time, based on the run-time (actual) type of the object. For non-virtual members, the implementation is resolved at compile time (when you compile), based on the declared type of the reference. For example: public class A { virtual public string Foo() { return "A.Foo()"; } } public class B : A { override public string Foo() { return "B.Foo()"; } } void test() { A obj = new A(); MessageBox.Show(obj.Foo()); // "A.Foo()" obj = new B(); // Now, "obj" is still of declared type "A", but run-time type "B". MessageBox.Show(obj.Foo()); // "B.Foo()" } If instead you declared A.Foo without the virtual keyword and used new to hide this method in B, the second call to "obj.Foo" would still resolve to A.Foo, because obj is of declared type A.