I have a repository class that uses NPoco/PetaPoco to access data which reads from a common content table.
create table Content (
Id int not null identity primary key,
Type tinyint not null,
...
)
Then I have an abstract ContentBase class that other types inherit. The main difference between inherited types being the value of that type DB column value. They do have some additional columns per concrete content type, but that's not relevant here.
So. In order for my repository class to return any of the actual concrete classes I wanted to write a medhod:
public TContent Create<TContent>(string name, ...)
{
...
// SP executes a few insers and returns newly created data instance
return db.Single<TContent>(
new Sql.Builder.Append(";exec dbo.CreateContent #Type, #Name, ...", new {
Type = TContent.Type, // this is the problem
Name = name,
...
}));
}
As you can see I would require my base abstract class to define a static member to get the actual type value that should be accessible through generic type specification. And inheriting classes should set it according to their concrete type implementation.
The problem is of course that there's no such thing as abstract static members in C#.
How should I approach this problem in a way so that my repository will be able to provide Type value on its own without me providing it explicitly with the call? I would only like to provide generic class when calling it and get back correct concrete type.
Why does it have to be static member?
My method doesn't get an object instance of a particular type but it should create one. That's why I can't really have an instance member Type and read from that one while executing my repository method.
A possible start
As static members are shared among all instances and if this is base class all inheriting classes share the same member unless this class is generic. In that case we get a static member per generic type.
So I was thinking of adding an additional class between the base abstract and concrete classes:
public abstract class ContentBase
{
...
}
public abstract class ContentBase<TConcrete>
where TConcrete: ContentBase<ContentBase> // is this constraint ok?
{
public static ContentType Type = ???;
}
and then concrete classes:
public class ContentOne : ContentBase<ContentOne>
{
???
}
And as said I should be able to call my repository method as:
repo.Create<ContentOne>(name, ...)
where within this method repository should be able to access static member of generic type provided by the call...
Even with your idea of having an abstract ContentBase class, you won't be able to access a custom behavior for each derived class; here is a small test i tried to see if your idea could be used:
public abstract class ContentBase<T>
{
public static Func<string> TypeLocator { get; set; }
static ContentBase()
{
TypeLocator = () => typeof(T).Name;
}
}
public class Content1 : ContentBase<Content1> {
private static string Content1Type = "The type of Content 1";
static Content1()
{
TypeLocator = () => Content1Type;
}
}
public class Content2 : ContentBase<Content2> {}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Content1.Type => " + GetObject<Content1>()); // Content1
Console.WriteLine("Content2.Type => " + GetObject<Content2>()); // Content2
}
private static string GetObject<TContent>() where TContent: ContentBase<TContent>
{
var typeLocator = typeof(ContentBase<TContent>).GetProperties()[0].GetValue(null, null) as Func<string>;
return typeLocator.Invoke();
}
}
The best you can get is the type of the TContent, which may be enough for you to explore the mapping proposition below.
I don't really see a way to implement abstract static members, but you could resort to an external registering dictionary living as a singleton throughout your program which would be used as the mapper between your Type and your Type.DBType
public TContent Create<TContent>(string name, ...)
{
...
// SP executes a few insers and returns newly created data instance
return db.Single<TContent>(
new Sql.Builder.Append(";exec dbo.CreateContent #Type, #Name, ...", new {
Type = RegisteredTypes[typeof TContent],
Name = name,
...
}));
}
Unfortunately the answer of "You Can't!" seems to have a concrete reason with no obvious workaround until C# 8 where it is directly supported.
Static members of non-static classes don't really belong to the same class as their non-static counterparts. The static parts really belong to a completely different class (a static class) whose name is made up by, and only known to, the compiler.
The slight-of-hand that the compiler plays to hide this fools you into thinking that it should be possible. If the compiler didn't hide the fact that there really is no such thing as a class with both static and non-static members, it would be more obvious that the name of the static class is unknown to the non-static class in the same way that references to any other classes referenced by your class are not directly available.
As of C#-8 you can define static methods (and therefore properties but not fields) in an interface so the problem is completely solved if you are not trapped behind a legacy barrier.
Related
I've created an abstract class, lets call it FooBarizable, that is the parent of 2 clases(more in the practice), Foo and Bar. Now, I have a FooBarizableManager that manages Foo and Bar classes, depending on his type. And from this FroobarizableManager, I want to call getFooBarizables(). Let's see the structure:
FooBarizable.cs:
public abstract class FooBarizable{
public string Name { get; set; }
public static IEnumerable<FooBarizable> GetFooBars(){
throw new NotImplementedException();
}
}
Foo.cs:
public class Foo : FooBarizable{
public static IEnumerable<FooBarizable> GetFooBars(){
return API.getFoos();
}
}
Bar.cs:
public class Bar : FooBarizable{
public static IEnumerable<FooBarizable> GetFooBars(){
return API.getBars();
}
}
FooBarizableManager.cs:
public class FooBarizableManager {
private Type type;
public FooBarizableManager(Type _t){
this.type = _t;
}
public void showFooBarizables(){
MethodInfo method = type.GetMethod("GetFooBars");
IEnumerable<FooBarizable> FooBars = (IEnumerable<FooBarizable>)method.invoke(null, null);
show(FooBars);
}
...
}
So, my problem is that I want to get the object collection from the manager, using the type, but enforce child classes to implement getFooBars() method.
Problems I've faced:
.Net does not allow to define static abstract methods, so I cannot create public static abstract IEnumerable<FooBarizable> GetFooBars() and enforce child class to implement it.
The way that is implemented does not enforce the implementation of the method in child classes, but I try to at least throw a NotImplementedException. The problem is that when I call MethodInfo method = type.GetMethod("GetFooBars"); in the manager, if the subclase does not implements the method, method is null, and NullPointerExceptionis called instead.
I've tried to create an instance method instead of static a static one, it solves the enforce problem because child classes have to implement it, But it does not seem correct to me to create an unnecessary instance to call a method.
So, is there any solution to enforce child classes to implement getFooBar() method? if not, how can I throw the NotImplementedException instead of NullPointerException?
is there any solution to enforce child classes to implement getFooBar() method?
Not for static methods. Static methods are tied to the specific class, so they can't be inherited, nor abstract or virtual.
If you want to make the method polymorphic it needs to be an instance method.
how can I throw the NotImplementedException instead of NullPointerException
The result you're getting that exception is because the type does not have a GetFooBars method, so method is null. So you could check for null first:
public void showFooBarizables(){
MethodInfo method = type.GetMethod("GetFooBars");
if(method == null)
throw new NotImplementedException();
IEnumerable<FooBarizable> FooBars = (IEnumerable<FooBarizable>)method.invoke(null, null);
show(FooBars);
}
But throwing that exception is a little misleading because it may seem to the caller that the showFooBarizables method is not implemented, not the underlying GetFooBars.
Since these method seem to be factory methods, perhaps you need a factory for each type instead? It seems like you are trying to use generics as a replacement for overloads. Factory methods generally aren't generic since they have to have different logic for each type. You could create a "base" factory that contains common code, then sub-class the factory for each specific type.
Of course .NET doesn't allow you to write virtual static methods :)
The whole point of virtual methods is that when you call the Base.DoSomething method on an instance of type Derived, it's the code in Derived.DoSomething that executes. But that means you need the instance to know its actual runtime type, so that you know what method is really supposed to be executed.
A typical alternative is to use some form of a factory interface. That is, instead of querying Foo.GetFooBars or Bar.GetFooBars, you'll get an instance of a provider of the relevant instance type, e.g. Fooizer.GetFooBars and Barizer.GetFooBars, where both Fooizer and Barizer implement IFooBarProvider. GetFooBars doesn't fit into the FooBarizable interface - because that's not where it belongs. Object-oriented design, responsibility, substitution principles and all that :)
Then, if you need to enforce the implementation in code (e.g. to make sure someone doesn't forget to implement the proper provider), you could make an abstract instance method or property on your type:
public abstract class FooBarizable
{
protected abstract IFooBarProvider GetDefaultProvider();
}
Depending on what you're actually trying to do, it might make sense to make those classes generic. Or not :)
You cannot force child classes to define a static methods. As you noted, abstract methods cannot be static, and interfaces work with instances only. I think you are trying to put too much into a single class. It looks like your trying to create some franken-factory. Instead just separate the factory functionality and the abstract parent object.
public abstract class FooBarizable {
public string Name { get; set; }
}
Factory example:
public static class FooBarizableFactory {
public static IEnumerable<FooBarizable> GetFooBars(Type type){
var parentType = typeof(FooBarizable);
if (!parentType.IsAssignableFrom(type))
throw new ArgumentException("Not a FooBarizable");
switch(type.Name) {
case "Foo":
return new List<Foo>() { new Foo () };
case "Bar":
return new List<Bar>() { new Bar() };
default:
throw new ArgumentException("Not a known FooBarizable");
}
}
}
Usage:
var fooBars = FooBarizableFactory.GetFooBars(typeof(Foo));
Demo of idea.
.Net does not allow to define static abstract methods
Because C# compiler makes static as abstract and sealed. So you can't make it just abstract or sealed.
The problem is that when I call MethodInfo method =
type.GetMethod("GetFooBars"); in the manager, if the subclase does not
implements the method, method is null, and NullPointerExceptionis
called instead.
I said static is abstract and sealed. So because of it's sealed derived class will not have GetFooBars method.
You can use the BindingFlags.FlattenHierarchy flag. That way it will check also protected and public static classes of base classes. If It's not implemented on derived class it will check base class. So in your stiuation base class GetFooBars will called, if the derived one does not have this method.
There's no way to enforce static methods via any form of inheritance or polymorphism, but a potential workaround would be to implement an extension method(s) for FooBarizable, so that any class that inherits it will have access to the extension.
Static methods are not related to the object (instance) of the class, it is always related to the class itself.
One way to enforce the implementation of a method would be the use of an interface.
Another way, and this is what I think you want, since this method will have different behavior in different instances, would be the use of abstract methods.
public abstract class AbstractClass
{
public abstract int MustIMplementThis(string param1);
}
public class ChildClass : AbstractClass
{
public override int MustIMplementThis(string param1)
{
throw new NotImplementedException();
}
}
All classes that inherits from AbstracClass will have to implement the methods listed on the parent class.
I do have a class, which is defined as:
public abstract class Singleton <T> : BaseObject
where T : Singleton <T>
{
}
I want to define an array of those generic singletons somewhere else. Something like
public MonoSingleton[] singletons;
How can I retrieve the proper type of that generic (that seems to be recursive, as you may see)? How can I write this out?
Are you trying to do the 'curiously recursive template pattern', like this?
class CuriouslyRecursiveBase<T>
{
}
class CuriouslyRecursiveDervied<T> : CuriouslyRecursiveBase<T>
{
}
class MyClass : CuriouslyRecursiveBase<MyClass>
{
}
To instantiate the derived from the base, you just use:
class CuriouslyRecursiveBase<T>
{
public static void InstantiateDerived()
{
T instance = (T)Activator.CreateInstance(typeof(T));
}
}
Since T is actually the derived type (MyClass) and curiously is also type (CuriouslyRecursive<MyClass>).
Specifically applied to your problem:
// Create a common interface that all singletons use. This allows
// us to add them all to a list.
interface ISingleton { }
class Singleton<T> : ISingleton
{
// Store our list of ISingletons
static List<ISingleton> instances = new List<ISingleton>();
static T instance;
protected Singleton() { }
public static T GetInstance()
{
// Either return the existing instnace, or create a new one
if (Singleton<T>.instance == null)
{
Singleton<T>.instance = (T)Activator.CreateInstance(typeof(T));
// Use a common interface so they can all be stored together.
// Avoids the previously mentioned co-variance problem.
// Also, compiler isn't built to follow curious recursiveness,
// so use a dynamic statement to force runtime re-evaluation of
// the type hierarchy. Try to avoid dynamic statements in general
// but in this case its useful.
instances.Add((dynamic)Singleton<T>.instance);
}
return Singleton<T>.instance;
}
}
class MyClass : Singleton<MyClass>
{
}
public static void Main()
{
MyClass my = MyClass.GetInstance();
}
More info:
http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Using design-time code, you'll be able to get the type by using the typeof operator and giving some argument to the generic parameter:
typeof(Singleton<SomeImplementationOfBaseObject>)
Or
typeof(Singleton<>)
But there's an alternative: reflection.
Type singletonType = Type.GetType("NamespaceA.NamespaceN.Singleton`1");
The 1 part is the number of generic parameters. If you've something like Class<T, S> it would be 2 and so on.
Note that using reflection you don't need to give the generic argument. You can get the type with the generic parameter anyway. In order to give the generic argument, you would do this:
Type genericType = singletonType.MakeGenericType(typeof(SomeImplementationOfBaseObject));
Or if you want to get it directly, you would do this:
Type singletonType = Type.GetType("NamespaceA.NamespaceN.Singleton`1[[NamespaceA.NamespaceN.SomeImplementationOfBaseObject]]");
The string inside [[ ]] its the full name for the type passed as generic argument. Note that if the generic type isn't the same assembly as the executing one, you'll need to provide an assembly qualified name (for example, "NamespaceA.MyClass, MyAssembly").
UPDATE
The OP said in some comment:
If I do use: public Singleton<BaseObject>[] singletons;, it warns me
with: 'error CS0309: The type BaseObject' must be convertible to
Singleton' in order to use it as parameter 'T' in the
generic type or method 'Singleton'
This is another problem: you can't do covariance in classes. For doing such thing, you'll need an interface like this:
public interface ISingleton<out TBaseObject> where TBaseObject : .........
And make the Singleton<T> class implement it.
Thus, you can create such array this way:
public ISingleton<BaseObject>[] singletons;
Covariance lets you upcast generic parameters and it's limited to interfaces and delegates.
Learn more here:
http://msdn.microsoft.com/en-us/library/ee207183.aspx
I have simple base class with single static field. I have numerous classes that derive from this base class. When I create a derived class, it causes invocation of the base classes static ctor which initializes the static field (Works as expected). The problem is that when I create another derived class, that inherits from same base, the static field in the base is still null, why???? It was initialized by the first class I instantiated.
Should not static fields in base classes have global allocation and be visible (ie. shared) to all derived classes?
My model:
class Base<T>
{
protected static object s_field = null;
static Base { s_field = new object(); }
}
class Derived1<T> : Base<T>
{
}
class Derived2<T> : Base<T>
{
}
// ... later in the program
Derived1<int> instance1 = new Derived1<int>(); // initializes static field (s_field in base class) for all derived types
Derived2<double> instance2 = new Derived2<double>(); // the static field is null
(I can see this through the debugger, but should it not already have been initialized by previous line??)
Since you have changed your code i believe you need to understand how generics works in .NET.
Static in generics behaves a bit different than in normal cases. For each unique open type T you provide, the base class maintains unique static member value.
You create another instance of open type double for the same base class via Derived < double > then youll see the concept what i am talking about.
Here a sample code to demonstrate more clearly :
public class Base<T>
{
public static string str = null;
static Base()
{
str = "hello";
Console.WriteLine("Ctor cald");
}
}
public class Derived1<T> : Base<T>{}
public class Derived2<T> : Base<T> { }
public partial class Program
{
public static void Main()
{
Derived1<int> derv = new Derived1<int>();
Derived2<double> derv2 = new Derived2<double>();
Derived2<double> derv3 = new Derived2<double>();
Console.ReadKey();
}
}
Here you shall see only 2 calls for the static Ctor.
I realized my mistake! Wow, the base class is actually a template class: Base<T>. When I create object of the base like this new Derived<int>(), new Derived<double>(), new Derived<object>(), these are completely different types and therefore the static field rules are different, my understanding is that the static field will be allocated for family of type T.
I have corrected the example above to reflect this (in the initial post).
Whole question changes when you put generics into the picture. Your understanding on inheritance of static members works as expected without generics and when Generics are in places, still the concept is valid with the exception that, Generics creates different types at run time.
Base<int> and Derived1<int> share the same static member where as Derived1<decimal> would be a different type than Base<int> at run time which doesn't share the static member with.
I have just learned how to mask a base class member (using new) but am missing the point as to why I would want to do that. Does masking provide us with a certain level of protection as is the case in using encapsulation? Please advise.
You will very rarely use "new" to mask a base class member.
It's mainly used for the cases where the derived class had the member first, and then it was added to the base class --- the same name for a different purpose. The new is there to that you acknowledge that you know you are using it differently. When a base member is added in C++, it just silently merges the existing method into the inheritance chain. In C#, you will have to choose between new and override, to show you know what is happening.
It's not just used for masking. It actually breaks the inheritance chain, so if you call the base class method, the method in the derived class will not be called (just the one in the base class).
You're essentially creating a new method that has nothing to do with the base class method. Hence the "new" keyword.
Keeping that in mind the "new" keyword can be used if you want to define a method with the same signature as a base type method, but having a different return type.
The only valid safe examples that I've come across is being more specific with return types or providing a set accessor on a property. I'm not saying those are the only ones, but that's all I've found.
For example, suppose you have a very simple base that looks like this:
public abstract class Base
{
public string Name { get; protected set; }
public Base(string name)
{ Name = name; }
}
You could have a derived that looks more like this:
public class Derived : Base
{
public new string Name
{
get { return base.Name; }
set { base.Name = value; }
}
public Derived(string name) : base(name)
{ }
}
Assuming business rules allows this one specific Derived to have a changeable name, I believe this is acceptable. The problem with new is that it changes behavior depending on what type the instance is viewed as. For example, if I were to say:
Derived d = new Derived("Foo");
d.Name = "Bar";
Base b = d;
b.Name = "Baz"; // <-- No set available.
In this trivial example, we're fine. We are overriding the behavior with new, but not in a breaking way. Changing return types requires a bit more finesse. Namely, if you use new to change a return type on a derived type, you shouldn't allow that type to be set by the base. Check out this example:
public class Base
{
public Base(Base child)
{ Child = child; }
public Base Child { get; private set; }
}
public class Derived
{
public Derived(Derived child) : base(child)
{ }
public new Derived Child
{ get { return (Derived)base.Child; } }
}
If I could set Child on the Base class, I could have a casting problem in the Derived class. Another example:
Derived d = new Derived(someDerivedInstance);
Base b = d;
var c = b.Child; // c is of type Base
var e = d.Child; // e is of type Derived
I can't break any business rules by treating all of my Derived classes as Bases, it's just convenient to not type check and cast.
I have just learned how to mask a base class member (using new)
FYI this feature is usually called "hiding" rather than "masking". I think of "masking" as clearing bits in a bit array.
am missing the point as to why I would want to do that.
Normally you don't want to. For some reasons to use and not use this feature, see my article on the subject from 2008:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx
Does masking provide us with a certain level of protection as is the case in using encapsulation?
No, it does not.
What you are referring to is called Name Hiding. It is mostly a convenience feature. If you are inheriting from a class for which you do not control the source using new will let you change the behavior of a method even if it wasn't declared as virtual (or completely change the signature if it is virtual). The new keyword simply suppresses a compiler warning. You are basically informing the compiler that you are intentionally hiding the method from a parent class.
Delphi had the reintroduce keyword for the same reason.
What does this buy you other than a suppressed warning? Not a whole lot. You can't access the new method from a parent class. You can access it from an interface if your child class directly implements the interface (as apposed to inheriting it from its parent class). You can still call the parent class' member from the child. Any additional descendants of your class will inherit the new member rather than the one in the parent.
This is actually called member hiding. There are a couple of common scenarios where this can be appropriately used.
It allows you to work around versioning issues in which either the base or derived class author unwittingly creates a member name that collides with an existing identifier.
It can be used to simulate covariance on return types.
Regarding the first point...it is possible that an author of a base class could later add a member with the same name as an exisiting member in a derived class. The base class author may not have an knowledge of the derived classes and thus there is no expectation that she should avoid name collisions. C# supports the independent evolution of class hierarchies using the hiding mechanisms.
Regarding the second point...you may want a class to implement an interface that dictates a certain method signature and so you are locked into returning instances of a certain type only while at the same time you have subclassed that type and would really like for callers to see the concrete type instead. Consider this example.
public interface IFoo { }
public class ConcreteFoo { }
public abstract class Base
{
private IFoo m_Foo;
public Base(IFoo x) { m_Foo = x; }
public IFoo Foo { get { return m_Foo; } }
}
public class Derived
{
public Derived(ConcreteFoo x) : base(x) { }
public new ConcreteFoo Foo { get { return (ConcreteFoo)base.Foo; } }
}
I have a container class that has a generic parameter which is constrained to some base class. The type supplied to the generic is a sub of the base class constraint. The sub class uses method hiding (new) to change the behavior of a method from the base class (no, I can't make it virtual as it is not my code). My problem is that the 'new' methods do not get called, the compiler seems to consider the supplied type to be the base class, not the sub, as if I had upcast it to the base.
Clearly I am misunderstanding something fundamental here. I thought that the generic where T: xxx was a constraint, not an upcast type.
This sample code basically demonstrates what I'm talking about.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericPartialTest
{
class ContextBase
{
public string GetValue()
{
return "I am Context Base: " + this.GetType().Name;
}
public string GetOtherValue()
{
return "I am Context Base: " + this.GetType().Name;
}
}
partial class ContextSub : ContextBase
{
public new string GetValue()
{
return "I am Context Sub: " + this.GetType().Name;
}
}
partial class ContextSub
{
public new string GetOtherValue()
{
return "I am Context Sub: " + this.GetType().Name;
}
}
class Container<T> where T: ContextBase, new()
{
private T _context = new T();
public string GetValue()
{
return this._context.GetValue();
}
public string GetOtherValue()
{
return this._context.GetOtherValue();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Simple");
ContextBase myBase = new ContextBase();
ContextSub mySub = new ContextSub();
Console.WriteLine(myBase.GetValue());
Console.WriteLine(myBase.GetOtherValue());
Console.WriteLine(mySub.GetValue());
Console.WriteLine(mySub.GetOtherValue());
Console.WriteLine("Generic Container");
Container<ContextBase> myContainerBase = new Container<ContextBase>();
Container<ContextSub> myContainerSub = new Container<ContextSub>();
Console.WriteLine(myContainerBase.GetValue());
Console.WriteLine(myContainerBase.GetOtherValue());
Console.WriteLine(myContainerSub.GetValue());
Console.WriteLine(myContainerSub.GetOtherValue());
Console.ReadKey();
}
}
}
Edit:
I guess my confusion comes from that one can do this
class SomeClass<T> where T: AnotherType, new()
{
T foo = new T();
}
And I expected T to be T even though I understand the compiler would view T as having AnotherType's interface. I assumed the typing of T would happen at run-time even if the interface of T was set at compile time. The T foo declaration seems misleading here because it is really doing
AnotherType foo = new T();
Once I understand that it is not really declaring foo as type T, it is understandable why the new method hiding wouldn't work.
And that's all I have to say about that.
Methods declared new have no relation (from the compiler's perspective) to methods with the same name/signature in the base class. This is simply the compiler's way of allowing you to define different methods in derived classes that share a signature with a method in their base class heirarchy.
Now, with regard to your specific case, realize that generics have to compile to a single set of bytecode regardless of the types that are supplied as generic parameters. As a result, the compiler only knows about the method and properties that are defined on the generic type T - that would be the base type you specify in the generic constraint. The compiler knows nothing about the new methods in your derived type, even if you create an instance of a generic type with the derived type as the parameter. Therefore calls in the generic class will always go to the methods of the base type.
There's a lot of confusion about new/virtual/override; take a look at this SO question - Jason and Eric's answers are excellent. Jon Skeet's answer to a similar question may also help you understand why your implementation behaves the way it does.
There are two possible ways for you to work around this issue:
Perform a conditional cast (based on runtime type information) to the derived type (or an interface) in your generic class. This breaks encapsulation and adds undesirable coupling. It's also fragile if implemented poorly.
Define an interface that you use in your generic constraint that exposes the methods you care about. This may not be possible if the code you are deriving from is not something you can change.
Add another layer - inherit your generic not from your third party class but from a new class which in turn inherits from the third party. In this new class you can define the method in question as new virtual. If all your code never references the third part class directly, it should work