I have the following class definition:
public abstract class BaseExample<T> where T : BaseExample<T>
{
public abstract T Clone(T original);
}
and its inheritances
public class Example01 : BaseExample<Example01>
{
public override Example01 Clone(Example01 original)
{
return this; // not the actual implementation
}
}
public class Example02 : BaseExample<Example02>
{
public override Example02 Clone(Example02 original)
{
return this; // not the actual implementation
}
}
How to declare a variable with the type or the base class? Since the following declaration doesn't compile:
private BaseExample<T> declarationA;
private BaseExample<T> declarationA;
private BaseExample declarationB;
It won't work as whatever you assign to generic type T cannot really ever be BaseExample<T>.
BaseExample<int> declarationA;
in case above int can't really be BaseExample<int> (int != BaseExample<int>)
I need to have a instance of BaseExample that could receive both Example01 or Example02 values. e.g.: BaseExample a = new Example01()
You can't - BaseExample<Example01> and BaseExample<Example02> are different types. There's not a base type (other than object) that could hold either type.
Suppose you could:
BaseExample a = new Example01();
what would the return type of a.Clone() return?
If your code is within a generic class ot method, then you could:
public T MyMethod<T>(T value) where T : BaseExample<T>
{
BaseExample<T> a = value;
return value.Close();
}
But you'd then have to specify the type when calling the method, e.g.
Example01 a1 = new Example01();
Example01 a2 = MyMethod(a1); // MyMethod<Example01> is inferred by the compiler
As mentioned, because Generic<T1> and Generic<T2> are different classes, you cannot assign them to the same variable.
One way I get around this is to use a non-generic base class, such that
public abstract class BaseExample { ... }
public abstract class BaseExmmple<T> : BaseExample
where T : BaseExample<T>
{ ... }
This can be made more safe by implementing an internal abstract member, such that outside classes cannot implement BaseExample.
If you wish to be able to call .Clone() from an object held in a variable of the non-generic type, you should implement an object-returning form which is wrapped by the generic class to call the generic form.
Related
I have an abstract class but and 6 different implementations of it. Now for one of them I would like to add an extra public method but would not like to add it to the abstract class because the other 5 implementations don't need it.
Is there a way of implementing this? I am getting an error when I add this new method without it being in the abstract class.
Here is the code:
namespace Results.Parser
{
public abstract class Parser<T> where T: ReportItem
{
public abstract string GetNodeName();
public abstract IEnumerable<ReportItem> ParseXml(TextReader stream);
public abstract List<ReportItem> SumValueOfDuplicateRows(List<T> reportList);
public virtual bool MeetsCriteria(ReportItem reportItem)
{
return reportItem.Value.SafeConvertToDecimal() != 0;
}
}
}
public class ElementParser : Parser<ReportItem>
{
public override string GetNodeName()
{
return "Element";
}
public override List<ReportItem> SumRiskValueOfDuplicateRows(List<ReportItem> reportList)
{
// do something
}
public void SerializeXml(TextReader stream)
{
//new method which is not in abstract class
}
public override IEnumerable<ReportItem> ParseXml(TextReader stream)
{
//do something
}
}
namespace Results.Producer
{
public class RepositoryManager
{
private void GetResponse(TextReader stream)
{
var parser = new ElementParser();
parser.SerializeXml(stream);
}
}
I am getting an error when I add this new method without it being in the abstract class.
A superclass reference to a subclass instance can't access methods not defined in the super class. You will need to explicitly cast your reference to a subclass reference type to be able to access the extra method from the subclass.
Let A be the abstract class and let B be the class where you have an extra method called extra. Let a be a reference of type A to an instance of type B. To access the extra method in B, do this :
((B)a).extra();
That being said, if only one of the classes needs additional behavior that is different, you should consider using composition over inheritance. See this answer that explains the famous duck problem that is similar to the situtation you are in currently
Ok, I have a number of different classes deriving from a base class.
This base class is an abstract containing commom methods.
One of the methods is a Copy method, wich should be present in all derived classes, so, I've put it in the base class.
BUT, I want it to return the derived type not the base nor object.
The solution I got for that, is using a type paramter:
abstract class CopyableClass<T>
{
public abstract T Copy();
}
class DerivedClass : CopyableClass<DerivedClass>
{
public override DerivedClass Copy()
{
//do what is needed for copy and return a new DerivedClass
}
}
So, the main purpose here is to
Remove the type parameter in the base class and still make the method return the corresponding derived type.
One workaround.
The best thing I could do so far is one of the comments below, but it still uses a generic parameter
abstract class BaseClass
{
//base methods not related to deriving type
}
interface ICopyable<T>
{
T Copy();
}
class DerivedClass : BaseClass, ICopyable<DerivedClass>
{
public DerivedClass Copy()
{
//do what is needed for copy and return a new DerivedClass
}
}
You can't really. The base class can't possibly know all the future implementations. You'll have to resort to a generic abstract class (like you did) type or a generic Copy method.
public abstract class CopyableClass
{
public abstract T Copy<T>() where T : CopyableClass;
}
public class DerivedClass : CopyableClass
{
public override T Copy<T>()
{
if(typeof(T) != typeof(DerivedClass))
throw new ArgumentException();
// return your copy
}
}
Or, if you want to generalize the type check in your base class:
public abstract class CopyableClass
{
public T Copy<T>() where T : CopyableClass
{
if(GetType() != typeof(T))
throw new ArgumentException();
return (T) Copy();
}
protected abstract CopyableClass Copy();
}
public class DerivedClass : CopyableClass
{
protected override CopyableClass Copy()
{
return // Your copy;
}
}
Note that the second method puts alot of trust into the implementation of the derived class as it'll blindly cast the return value of the abstracted method. The compiler will let you return another type, implementing CopyableClass, in a derived type but it will be a runtime error. This is not a problem if you have the absolute control over all of the derived implementations (ie your abstract class also have an internal constructor).
This solution involves a middle class but I think its more inline with what the you are looking for. At least you get the possible benefit of isolating your copy code
public abstract class BaseClass
{
}
public abstract class CopyableClass<T> : BaseClass
where T: BaseClass, new()
{
public T Copy()
{
var copy = new T(); // Creating a new instance as proof of concept
return copy;
}
}
public class DerivedClass : CopyableClass<DerivedClass>
{
}
You actually want to implement copy in the base class and have it return T. This will make is so you call it with a type argument and it returns that type.
public static T Copy<T>() where T : CopyableClass
{
T retVal = new T();
// do whatever copying is required
return retVal;
}
To call it you do;
DerivedClass d = Copy<DerivedClass>();
Your code to actually do the copy might be a bit more work to make generic but it's worth the effort given you will have a single implementation of Copy() that works for any derived type. I don't know what logic belongs in the method so I've just stubbed things out. Also, I'd recommend checking out generics in general. They're often the best option for things like this. If your implementations need to be unique to the base class' keep the same method definition but make it abstract and then override it in the base classes.
This will allow you to case this base class to the derived type and return it.
public abstract class BaseClass<TDerived> : where TDerived: BaseClass<TDerived>
{
public TDerived DoSomethingCommon(string param)
{
var derivedType = (TElement)this;
//do something.
return derivedType;
}
}
I have an Object called CAR declared as follows:
public class Car{
public int NumberOfWheels;
}
and using another class I can retrieve three of its subclasses.
As follows:
public TruckA getCarA(int param){
return new TruckA () {NumberOfWheels = param}
}
public TruckB getCarB(int param){
return new TruckB () {NumberOfWheels = param}
}
public TruckC getCarC(int param){
return new TruckC () {NumberOfWheels = param}
}
How do I write in using generics ?
(I know it is too simple, I need an example for a more complicated case)
I want to create a method that creates a new (T), enters the parameter and returns it.
something like
public TruckC getCarC(int param){
return getTruck<TruckC>(param)
}
Only that :
1. TruckA/B/C dont have constructor.
2. Car has no constructor. initialized using {}.
3. The method should receive only classes that derive from Car so that it can use its initialization ( {} ).
(something equivalent to ?? extends ? in java generics)
Possible ?
Thanks.
private static T GetTruck<T>(int param) where T : Car, new()
{
return new T() {NumberOfWheels = param} ;
}
You need to do this using generic type constraints. These let you make requirements about the type that is passed.
It would look something like this:
public static T GetCar<T>(int param)
where T : Car, new() // Must inherit from Car, must have a parameterless constructor
{
return new T() { NumberOfWheels = param };
}
try this :
public T getCarC<T>(int param) where T : Car, new()
{
T truck=new T();
truck.NumberOfWheels = param;
return track;
}
Generics are the most powerful feature of C# 2.0. Generics allow you to define type-safe data structures, without committing to actual data types.
When deriving from a generic base class, you must provide a type argument instead of the base-class's generic type parameter:
public class BaseClass<T>
{...}
public class SubClass : BaseClass<int>
{...}
If the subclass is generic, instead of a concrete type argument, you can use the subclass generic type parameter as the specified type for the generic base class:
public class SubClass<T> : BaseClass<T>
{...}
When using the subclass generic type parameters, you must repeat any constraints stipulated at the base class level at the subclass level. For example, derivation constraint:
public class BaseClass<T> where T : ISomeInterface
{...}
public class SubClass<T> : BaseClass<T> where T : ISomeInterface
{...}
Or constructor constraint:
public class BaseClass<T> where T : new()
{
public T SomeMethod()
{
return new T();
}
}
public class SubClass<T> : BaseClass<T> where T : new()
{...}
I'm trying to use generics in inheritance with structs, see.
public class AuditLogEntry : ObjectBase<AuditLogEntry.AuditLogEntryStruct>
{
private struct AuditLogEntryStruct
{
public int AuditID;
}
}
public abstract class ObjectBase<T>
{
}
It won't let me use private for my struct, as it throws the error:
Inconsistent accessibility: base class 'ObjectBaseAuditLogEntry.AuditLogEntryStruct>' is less accessible than class 'AuditLogEntry'.
However I don't really want to make my struct public.
Any ideas?
Thanks,
Alex
Follow on question:
Here is what we are trying to do:
class AuditLogEntry : ObjectBase<AuditLogEntry.AuditLogEntryStruct>
{
internal struct AuditLogEntryStruct
{
public int AuditID;
}
public int AuditID
{
get
{
return udtObject.AuditID;
}
set{
BeginEdit();
udtObject.AuditID = value;
}
}
class ObjectBase<T>
{
protected T udtObject;
protected T udtPreEditObject;
protected void BeginEdit()
{
if (!IsDirty)
{
IsDirty = true;
udtPreEditObject = udtObject;
}
}
}
I'm not sure how to achive this within making AuditLogEntryStruct public?
Thanks,
Alex
You can't derive a public class from a generic class when one or more of the type arguments aren't public
The types that any type derives from has to be as accessible as the deriving class, inculding any type parameters given as type arguments to the base class
if you have
public class publicClass{}
Any class can derive from A however if you changed it to
internal class internalClass{}
only other internal classes can derive from it.
The same is true if you passed either of the types as a type parameter. The first three below are valid the fourth is not
public class A : List<publicClass>{}
internal class B : List<internalClass>{}
internal class C : List<publicClass>{}
//not valid because D has wider accessibility than the close generic type List<internalClass>
public class D : List<internalClass>{}
EDIT
The language team at some point have had to make a decision whether to make a declaration as yours invalid or make any use of your type that resulted in illegal access to an inaccessible type invalid. In your case there would be several methods returning a type that would be inaccessible to all others than your class and a number of methods taking an argument of a type no other class could provide. So the only objects that would actually be able to use objects of your class would be objects of your class. You can solve that with composition instead of inheritance
public class AuditLogEntry
{
private ObjectBase<AuditLogEntry.AuditLogEntryStruct> _entry;
private struct AuditLogEntryStruct
{
public int AuditID;
}
}
public abstract class ObjectBase<T>
{
}
Consider this example:
public class Foo : List<Bar>
{
private struct Bar { }
}
var myFoo = new Foo();
...
var x = myFoo()[0]; // expression on the right side is of type Bar, yet Bar is inaccessible
UPDATE
What you are trying to achieve doesn't really require generics. You only access your structs inside ObjectBase<T> as if they were objects. You might as well change them to object and remove generic type altogether.
If you have some more logic that requires some sort of functionality from AuditLogEntryStruct to be accessable in ObjectBase<T>, you may extract an interface:
public interface IStructsWithSomeFunctionality { ... }
make your struct implement it and use it as your type parameter
public class AuditLogEntry : ObjectBase<IStructsWithSomeFunctionality> { ... }
I've got an abstract class like this;
public abstract PropertyBase
{
public static System.Type GetMyType()
{
return !!!SOME MAGIC HERE!!!
}
}
I'd like to subclass it, and when I call the static GetMyType(), I'd like to return the subclass's type. So if I declare a subtype;
public class ConcreteProperty: PropertyBase {}
then when I call
var typeName = ConcreteProperty.GetMyType().Name;
I expect 'typeName' to be set to "ConcreteProperty." I suspect there's no way to do it, but I'm interested if anyone out there knows a way to get this info.
(The particular problem I'm trying to solve is the verbosity of dependency properties in WPF; I'd love to be able to do something like this;
class NamedObject : DependencyObject
{
// declare a name property as a type, not an instance.
private class NameProperty : PropertyBase<string, NamedObject> { }
// call static methods on the class to read the property
public string Name
{
get { return NameProperty.Get(this); }
set { NameProperty.Set(this, value); }
}
}
And I almost have an implementation, but I can't quite get the info I need out of my NameProperty class.)
You can partially achieve (1-level of inheritance deep) using generics:
class PropertyBase<T>
{
public static Type GetMyType() { return typeof (T); }
}
// the base class is actually a generic specialized by the derived class type
class ConcreteProperty : PropertyBase<ConcreteProperty> { /* more code here */ }
// t == typeof(ConcreteProperty)
var t = ConcreteProperty.GetMyType();
The subclassing bit will not work, because a static method is tied to a type. It is a method of a type, not a method of an instance. The subtype does not contain the static methods of a base type, because they are different types and the static method is tied to the base type. Even though the compiler might allow you to call a static method of a base class as through a derived class, it will in reality call the method from the base class. It's just syntax sugar. For the same reason you cannot "override" static methods in subclasses because it would make little sense.
Just wondering why would need to do something like this?
var typeName = ConcreteProperty.GetMyType().Name;
Anyhow you know the type while calling the method, you can simply do this as well..
var typeName = typeof(ConcreteProperty).Name;
Just in case you need to do this, you can use "shadowing" to override the implementation of base class in child class.
public class ConcreteProperty : PropertyBase {
public new static Type GetMyType {
//provide a new implementation here
}
}