Consider the following very basic C# code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Random random = new Random();
for (int i = 1; i <= 100; i++)
{
int num = random.Next(1000);
string it_type;
if (num == 666)
{
System.Console.Write("Antichrist/satanistic trips get. Enjoy! ");
JonSkeet technician = new JonSkeet(); // Needs more Super::$tatic
technician.setup();
it_type = technician.getITType();
}
else
{
Whisperity technician = new Whisperity();
technician.setup();
it_type = technician.getITType();
}
System.Console.WriteLine(it_type + "... Prepare for next iteration.");
}
System.Console.ReadLine();
}
}
abstract public class ITTechnician
{
protected string itt_type = "Noname person.";
protected bool isJonSkeet = false;
public string getITType()
{
return this.itt_type;
}
abstract public void setup();
}
public class JonSkeet : ITTechnician
{
public override void setup()
{
this.itt_type = "Jon Skeet";
this.isJonSkeet = true;
}
}
public class Whisperity : ITTechnician
{
public override void setup()
{
this.itt_type = "Whisperity";
this.isJonSkeet = false;
}
}
}
How would I be able to set up a constructor in a way that the abstract class (abstract public void?) would require it and that I don't have to call technician.setup(); because the constructor takes care of setting the two internal variables. If I call the class functions the same name as the class itself, I get the following error:
Error 1 'Whisperity': member names cannot be the same as their enclosing
Also, my other question would be about optimization. Is there a way to define technician outside the if construct so something like the following could be executed: (This would omit having the classType technician = new classType(); lines twice, or is it unbypassable in C#?)
string it_type;
// Register 'technician' as a variable here.
if (num = 666)
{
technician = new JonSkeet();
}
else
{
technician = new Whisperity();
}
it_type = technician.getITType();
System.Console.WriteLine(it_type + "...");
Answer to your Question
You can provide a constructor with parameters in the abstract class.
abstract public class ITTechnician
{
public ITTechnician(string itt_type, bool isJonSkeet)
{
this.itt_type = itt_type;
this.isJonSkeet = isJonSkeet;
}
}
To construct a JonSkeet (if only it were so easy!)
JonSkeet jon = new JonSkeet("Jon Skeet", true);
Advice on Class Design
On a side note, I know this is a sample question, but you are not using object orientation well if a base class holds information that would differentiate classes that inherit from it.
Specifically this design would lead you to do things like
ITTechnician itt = GetSomeInstance();
if (itt.IsJonSkeet)
{
BehaviorA();
else
{
BehaviorB();
}
It is far cleaner to do something like
abstract public class ITTechnician
{
public abstract void Behavior();
// ...
}
public class JonSkeet
{
public override Behavior()
{
// Do awesome things
}
}
which allows the above code to be written as
ITTechnician itt = GetSomeInstance();
itt.Behavior();
How would I be able to set up a constructor in a way that the abstract
class would require it and that I don't have to call
technician.setup()
You don't need construct your logic to force the behavior of abstract class, but vice versa. Abstract class defines a stuf that has to be followed by the child.
If you create a simple parametless ctor in abstract class, which initializes the variables you need, whenever the child object will be constructed, the default ctor of abstract will be called before, so intialization will be executed.
To be more clear:
public class Child : Base
{
public Child(int x){
"Child".Dump();
}
}
public abstract class Base
{
public Base() {
//INIT VARIABLES HERE
"Base".Dump();
}
}
using these constructs like
vaar ch = new Child(); produces the result
"Base"
"Child"
If this is not what you're asking for, please clarify.
To discover a type at runtime, use GetType(). There's no need to create your own type string field.
The only thing that varies other than the intrinsic type in your class structure is IsJonSkeet. We can use a .NET property to implement this, which is a more modern and expressive way when compared to traditional private/protected fields with a Getter and maybe a Setter.
abstract public class ITTechnician
{
public bool IsJonSkeet { get; protected set; }
protected ITTechnician()
{
this.IsJonSkeet = false;
}
}
public class JonSkeet : ITTechnician
{
public JonSkeet()
{
this.IsJonSkeet = true;
}
}
public class Whisperity : ITTechnician
{
}
Now that your itt_type string field has been removed, Whisperity is the same as the base class, so there's no need for a constructor to do any initialisation - it will pick up the IsJonSkeet value of its parent automatically.
+1 for Eric J's class design tips, too. You should use the design of your hierarchy to encapsulate what varies and this makes your calling code much more transparent and the codebase easier to expand on in the future.
Related
I have read an article regarding the new keyword. It says it is used to hide methods. This is example they give:
using System;
namespace ConsoleApplication3
{
class SampleA
{
public void Show()
{
Console.WriteLine("Sample A Test Method");
}
}
class SampleB:SampleA
{
public void Show()
{
Console.WriteLine("Sample B Test Method");
}
}
class Program
{
static void Main(string[] args)
{
SampleA a = new SampleA();
SampleB b = new SampleB();
a.Show();
b.Show();
a = new SampleB();
a.Show();
Console.ReadLine();
}
}
}
Output:
Sample A Test Method
Sample B Test Method
Sample A Test Method
So my question isn't the new keyword used to instantiated an object? and its used to allocate memory for new created objects? Then how can method hiding be done using it? And is above example correct?
new is used for 3 different things. You could say there are 3 different keywords with the same name.
It's an operator, used to invoke constructors. Example: new object();
It's a modifier, used to hide an inherited member from a base class member. Example:
class Base {
public void MyMethod() {
//Do stuff
}
}
class Derived : Base {
public new void MyMethod() {
//Do other stuff
}
}
It's a generic type constraint, used to indicate that a generic type parameter has a parameterless constructor. Example:
class MyGenericClass<T> : where T : new() { ... }
Source: new
Isn't the new keyword used to instantiated an object?
Yes it is. Among other things.
then how can method hiding done using it?
The new keyword in the context of method and property definitions has another meaning than the new keyword used to instantiate objects. The new keyword in that context tells that there is a new start of the inheritance tree of that particular method or property. That's all.
Then how can method hiding be done using it? And is above example
correct?
Programming language syntax, grammar and semantics are just an arbitrary set of conventions and specifications. That is, C# can invent one, two or dozen of usages of a given keyword like new.
When new is used during a class member declaration, it means that you're re-using an identifier:
public class A
{
public string Text { get; set; }
}
public class B : A
{
new public int Text { get; set; }
}
As you can check in above code sample, B also implements a Text property, but since derives from A which has also defined a Text property, there's a naming collision.
The so-called new keyword can be used to re-use Text identifier and being able to implement another property Text which may behave absolutely different than the one implemented in the base class. See that Text on B is of type int!
The most important point here is that re-using identifiers isn't the same as using polymorphism, where a class method or property override must match base class' member signature:
public class A
{
public virtual string Text { get; set; }
}
public class B : A
{
public override string Text
{
get { return base.Text; }
set { base.Text = value; }
}
}
Also, re-used identifiers are dangerous:
public class A
{
public string Text { get; set; }
}
public class B : A
{
new public int Text { get; set; }
}
B b = new B();
b.Text = 4;
// Upcast B to A
A a = b;
a.Text = "Bye bye";
Console.WriteLine(a.Text); // Output: Bye bye
Console.WriteLine(b.Text); // Output: 4
See the output of Text. Since re-using identifiers isn't polymorphism, and in above case both are completely different properties, there's an A.Text and B.Text that can be set separately.
To hide an inherited member, declare it in the derived class by using the same member name, and modify it with the new keyword. For example:
public class BaseC
{
public static int x = 55;
public static int y = 22;
}
public class DerivedC : BaseC
{
// Hide field 'x'.
new public static int x = 100;
static void Main()
{
// Display the new value of x:
Console.WriteLine(x);
// Display the hidden value of x:
Console.WriteLine(BaseC.x);
// Display the unhidden member y:
Console.WriteLine(y);
}
}
/*
Output:
100
55
22
*/
You can read more in here
I often use
using (var context = new SomeDataContext(SomeDataContext.ConnectionString))
{
...
}
where
abstract class DataContextBase: DataContext { ... }
partial class SomeDataContext: DataContextBase
{
public const string DatabaseFile = "blablabla.mdf";
public static readonly string ConnectionString = string.Format(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename={0};Integrated Security=True", DatabaseFile);
}
Question: Is it possible to hide creation of SomeDataContext instance and ConnectionString deep into DataContextBase?
I want to define only file name in inherited classes
partial class SomeDataContext: DataContextBase
{
public const string DatabaseFile = "blablabla.mdf";
}
and to be able to create instances like this
var context = SomeDataContext.PropertyInBaseClassWhichCreatesInstanceOfInheritedClass;
P.S.: I add at first of how I tried to overcome the problem (without success tbh), but then I deleted it (I was making this post over hour!), because it makes question too noisy. It may looks easy at first, until you (or is it only me?) try to solve it. I tagged it dbml because of specific to DataContext things: you can't use singleton, etc.
Unfortunately, there isn't some sort of virtual static, and if you call SomeDataContext.StaticPropertyInBaseClass, it compiles to the same as DataContextBase.StaticPropertyInBaseClass. I think the best you can do is something like this:
// upside: simple SomeDataContext.Instance for external users
// downside: more code in SomeDataContext
partial class SomeDataContext : DataContextBase
{
private const string DatabaseFile = "blablabla.mdf";
public static SomeDataContext Instance
{
get
{
return new SomeDataContext(GetConnectionString(DatabaseFile));
}
}
}
abstract class DataContextBase
{
protected static string GetConnectionString(string databaseFile)
{
return string.Format(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename={0};Integrated Security=True", databaseFile);
}
}
// e.g. using (var context = SomeDataContext.Instance)
Or
// upside: just one line in child class
// downside: a little harder for external callers, with a little less type safety
// downside: as written, requires child class to have parameterless constructor
partial class SomeDataContext : DataContextBase
{
protected override string DatabaseFileInternal { get { return "blablabla.mdf"; } }
}
abstract class DataContextBase
{
protected abstract string DatabaseFileInternal { get; }
private string ConnectionString
{
get
{
return string.Format(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename={0};Integrated Security=True", DatabaseFileInternal);
}
}
public static T GetInstance<T>() where T : DataContextBase, new()
{
using (var tInst = new T())
return (T)Activator.CreateInstance(typeof(T), tInst.ConnectionString);
}
}
// e.g. using (var context = DataContextBase.GetInstance<SomeDataContext>())
I've got a class defined like this:
public abstract class Uniform<T>
{
public abstract string GlslType { get; }
...
}
And then a subclass defined like this:
public class UniformInt : Uniform<int>
{
public override string GlslType
{
get { return "int"; }
}
}
And then a method somewhere else that looks like this:
public static string GetCode<T>()
{
var sb = new StringBuilder();
var type = typeof(T);
sb.AppendFormat("struct {0} {{\n", type.Name);
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach(var f in fields)
{
sb.AppendFormat(" {0} {1};\n", f.FieldType.GetProperty("GlslType").GetValue(???), f.Name);
}
...
}
I'm having trouble filling in the ???s. I believe GetValue expects an instance of the object, but I don't really care what instance it is because they all return the same value. And AFAIK there's no such thing as a public abstract static readonly value, so I have to use properties.
So what can I put in place of those ???s to get back "int" (assuming one the fields was a UniformInt).
As a side: How can I limit fields to only field types that inherit Uniform<>?
You need an instance of UniformInt in order to get the value of a non-static property:
UniformInt someUniformInt = ...
f.FieldType.GetProperty("GlslType").GetValue(someUniformInt, null)
As a side: How can I limit fields to only field types that inherit Uniform?
bool isDerivesFromUniformOfInt = typeof(Uniform<int>)
.IsAssignableFrom(f.FieldType);
or if you don't know the type of T in advance:
bool isDerivesFromUniformOfT = typeof(Uniform<>)
.MakeGenericType(typeof(T))
.IsAssignableFrom(f.FieldType);
The problem is that since your property is not static the compiler doesn't know that they all return the same value. Since your UniformInt is not sealed, another user could inherit from it and override GlslType to return something else. Then UniformInt and all derived classes could be used for your GetCode<T>() method.
A static method would really be the best option. To make sure that you implement them on all classes (something you can't force because static methods can't be abstract) I would write a simple unit test that uses reflection to load all classes that inherit from Uniform<T> and check if they have the static property defined.
UPDATE
When thinking about how Attributes could help and after some experimenting I came up with the following. It definitely won't win a beauty contest but as a learning exercise it was helpful ;)
using System;
using System.Linq;
namespace StackOverflow
{
internal class StackOverflowTest
{
private static void Main()
{
string sInt = UniformInt.GlslType;
string sDouble = UniformDouble.GlslType;
}
}
public abstract class Uniform<B, T> // Curiously recurring template pattern
where B : Uniform<B, T>
{
public static string GlslType
{
get
{
var attribute = typeof(B).GetCustomAttributes(typeof(GlslTypeAttribute), true);
if (!attribute.Any())
{
throw new InvalidOperationException(
"The GslType cannot be determined. Make sure the GslTypeAttribute is added to all derived classes.");
}
return ((GlslTypeAttribute)attribute[0]).GlslType;
}
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
internal sealed class GlslTypeAttribute : Attribute
{
public string GlslType { get; private set; }
public GlslTypeAttribute(string glslType)
{
GlslType = glslType;
}
}
[GlslType("int")]
public class UniformInt : Uniform<UniformInt, int> // Curiously recurring template pattern
{
}
[GlslType("double")]
public class UniformDouble : Uniform<UniformDouble, double> // Curiously recurring template pattern
{
}
}
The GlslType is not static, so you need an object reference before you can access it's value. The subject of static properties in abstract classes has been covered extensively already, ie:
C#, implement 'static abstract' like methods
Can't define static abstract string property
Solution 1
Add static methods to all derived classes that return the GlslType. Nothing needs to be added to the base class. Can use unit testing + reflection to check for missing implementation. Suggested by Wouter de Kort.
Solution 2
Change Uniform<T> to make GlslType static:
public abstract class Uniform<T>
{
public static string GlslType { get { throw new NotImplementedException("Please override with \"new\" in derived class."); } }
...
}
Change UniformInt to "override" GlslType, keeping the static modifier:
public class UniformInt : Uniform<int>
{
public new static string GlslType
{
get { return "int"; }
}
}
Fill ??? with null, null:
sb.AppendFormat(" {0} {1};\n", f.FieldType.GetProperty("GlslType").GetValue(null,null), f.Name);
Solution 3
Use attributes instead. Something like:
[GlslType("int")]
public class UniformInt : Uniform<int>
{
}
Conclusion
All 3 of these solutions are pretty similar and seem to have the same drawbacks (can't enforce derived class to implement it). Throwing an exception via method 1 or 2 will help find errors quickly, or with 3 I can just skip over classes that don't have the attribute by modifying my fields condition.
I've been given a .NET project to maintain. I was just browsing through the code and I noticed this on a property declaration:
public new string navUrl
{
get
{
return ...;
}
set
{
...
}
}
I was wondering what does the new modifier do to the property?
It hides the navUrl property of the base class. See new Modifier. As mentioned in that MSDN entry, you can access the "hidden" property with fully qualified names: BaseClass.navUrl. Abuse of either can result in massive confusion and possible insanity (i.e. broken code).
new is hiding the property.
It might be like this in your code:
class base1
{
public virtual string navUrl
{
get;
set;
}
}
class derived : base1
{
public new string navUrl
{
get;
set;
}
}
Here in the derived class, the navUrl property is hiding the base class property.
This is also documented here.
Code snippet from msdn.
public class BaseClass
{
public void DoWork() { }
public int WorkField;
public int WorkProperty
{
get { return 0; }
}
}
public class DerivedClass : BaseClass
{
public new void DoWork() { }
public new int WorkField;
public new int WorkProperty
{
get { return 0; }
}
}
DerivedClass B = new DerivedClass();
B.WorkProperty; // Calls the new property.
BaseClass A = (BaseClass)B;
A.WorkProperty; // Calls the old property.
Some times referred to as Shadowing or method hiding; The method called depends on the type of the reference at the point the call is made. This might help.
https://msdn.microsoft.com/en-us/library/435f1dw2.aspx
Look at the first example here, it gives a pretty good idea of how the new keyword can be used to mask base class variables
(C#, VS2008) In a program I'm working on, I've got lots of objects that all have an ID and implement IComparable so that List<>-s of the various objects are easily searchable by ID. Since I hate copy/pasting code, I thought I'd abstract that bit of functionality down to a base class, like so:
using System;
namespace MyProg.Logic
{
abstract class IDObject : IComparable<IDObject>
{
private int miID;
public int ID
{
get { return miID; }
set { miID = value; }
}
public IDObject(int ID)
{
miID = ID;
}
#region IComparable<IDObject> Members
int IComparable<IDObject>.CompareTo(IDObject other)
{
return miID.CompareTo(other.miID);
}
#endregion
}
}
The drawback I see to that is that two separate classes that each inherit it would be directly comparable using .CompareTo() and I was hoping to enforce that each class that inherits from IDObject is only Comparable to others of the exact same class. So I was hoping to figure out how to do that and came up with this
using System;
namespace MyProg.Logic
{
abstract class IDObject : IComparable<T> where T : IDObject
{
private int miID;
public int ID
{
get { return miID; }
set { miID = value; }
}
public IDObject(int ID)
{
miID = ID;
}
#region IComparable<T> Members
int IComparable<T>.CompareTo(T other)
{
return miID.CompareTo(other.miID);
}
#endregion
}
}
But that gives a compile error of "Constraints are not allowed on non-generic declarations"
Looking at it, I'm sure there's a way to do something like that so that each class is only comparable to other instances of that same class, but I can't tease out the syntax.
You can use the Curiously Recurring Template Pattern to solve this problem.
abstract class Base<T> : IComparable<T> where T : Base<T> {
public int Rank { get; set; } // Order instances of derived type T by Rank
public int CompareTo(T other) { return Rank.CompareTo(other.Rank); }
}
class Foo : Base<Foo> {}
class Bar : Base<Bar> {}
static class Program {
static void Main() {
var foo1 = new Foo { Rank = 1 };
var foo2 = new Foo { Rank = 2 };
var bar1 = new Bar { Rank = 1 };
var bar2 = new Bar { Rank = 2 };
Console.WriteLine(foo1.CompareTo(foo2));
Console.WriteLine(bar2.CompareTo(bar1));
//error CS1503: Argument '1': cannot convert from 'Bar' to 'Foo'
//Console.WriteLine(foo1.CompareTo(bar1));
}
}
I think you've got bigger problems than just making sure that the derived class types are the same. You are also saddling the derived class with the responsibility to generate a unique ID. That requires the derived class to be aware what other IDs were assigned previously. Realistically, that requires a class factory. You'll need to enforce that by making the constructor of your abstract class protected.
Not very practical. If the ID is just an opaque number that establishes object identity then consider assigning the ID yourself. Use a static member to keep track of the last assigned one. Now it becomes simple, and you don't have to worry about derived class types anymore.