Given the following classes/interfaces defined in a base library:
public interface IWorkContext {
T Node<T>() where T : class, IHierachy<T>;
IHierachyItem Node();
}
public interface IHierachyItem {
int Id { get; set; }
string Title { get; set; }
}
public interface IHierachy<T> : IHierachyItem where T : IHierachy<T> {
T Parent { get; set; }
IList<T> Children { get; set; }
}
public class WorkContext {
public static IWorkContext Current {
get { return DependencyResolver.Current.GetService<IWorkContext>(); }
}
}
Which has the following implentation inside another library (that references the base library above):
public class DefaultWorkContext : IWorkContext {
// Nhibernate session
private readonly ISession _session;
public DefaultWorkContext(ISession session) {
_session = session;
}
public T Node<T>() where T : class, IHierachy<T> {
return _session.Get<T>(2);
}
public IHierachyItem Node() {
return Node<SiteMapNode>();
}
}
Where SiteMapNode exists in the same library (and is mapped to a database table):
public class SiteMapNode : IHierachy<SiteMapNode> {
public virtual int Id { get; set; }
public virtual SiteMapNode Parent { get; set; }
public virtual string Title { get; set; }
public virtual IList<SiteMapNode> Children { get; set; }
public SiteMapNode() {
Children = new List<SiteMapNode>();
}
}
I can say the following to access a node and get the parent:
var node = WorkContext.Current.Node();
var parentNode = ((IHierachy<SiteMapNode>)node).Parent;
var node2 = WorkContext.Current.Node<SiteMapNode>();
var parentNode2 = node2.Parent;
However i don't like either approach as option 1 requires a case and option 2 requires me to pass a default type.
Is it possible to refactor this sample so that i can access the Parent and Child the same way I get the Id and Title.
I hope i've explained the problem clear enough. I'd appreciate the help. Thanks
Your problem might be more clear if you used explicit types instead of var. Declaring a variable with var does not make the variable type dynamic, it just makes the compiler figure out what specific type the variable needs to be (and it can be dangerous because you don't know as clearly what type it determines).
So, having declared variables with a specific type (whether you know what that type is or not), you can then only access what that declared type knows unless you cast it appropriately.
I think in the end there is no way to accomplish exactly what you want without specifying a type at some point as a type argument (in angle-brackets) or an explicit cast. You apparently want to convert a non-specific iherited/implementing type to a handy specific type, but that requires telling the complier a specific type for it to become.
But you may get closer to what you'd like by changing your approach. What if you used a non-generic IHierarchy? (also correct the spelling) If...
public inetrface IHierarchy : IHierarchyItem
{
IHierarchy Parent { get; set; }
IList<IHierarchy> Children { get; set; }
}
...then any IHierarchy node variable could access node.Parent and node.Children... and also node.Id and node.Title because the IHierarchyItem is required and thus is known to IHierarchy.
This approach would handle the hierarchy aspects easily and allows polymorphism in your WorkContext.Current (etc) return values, but it would require explicit casting from there to access anything specific to a class outside of the defined members of IHierarchy. It's not clear how much of an issue that might be for your purpose.
You could also perhaps layer a generic IHierarchy<T> : IHierarchy on top of it to allow handling by a specific type without further casting. You might have to define one or both interface members explicitly rather than implicitly (in implementing classes) to avoid name collisions on the properties without generic type arguments.
EDITED TO ADD:
For example, something like:
public interface IHierarchy<T> : IHierarchy // Implies IHierarchyItem
where T : IHierarchy<T>
{ ... } // As you had it.
Then in your implementation class:
public SiteMapNode : IHierarchy<SiteMapNode> // Implies IHierarchy
{
private SiteMapNode _Parent;
private IList<SiteMapNode> _Children;
// Implicit implement of IHierarchyItem and members of SiteMapNode itself.
int Id { get; set; }
string Title { get; set; }
// Implicit implementation of IHierarchy<SiteMapNode> members
// These are also members of SiteMapNode itself.
SiteMapNode Parent
{
get { return _Parent; }
set { _Parent = value; }
}
IList<SiteMapNode> Children
{
get return _Children;
set _Children = value;
}
// Explicit implementation of IHierarchy members
// The interface prefix is required to distinguish these from the
// type-specific members above to declare different return types.
IHierarchy IHierarchy.Parent
{
get { return _Parent; } // Might need (IHierarchy) cast
set { Parent = (SiteMapNode)value; }
}
IList<IHierarchy> IHierarchy.Children
{
get { return _Children; } // Might need (IList<IHierarchy>) cast
set { _Children = (IList<SiteMapNode>)value; }
}
}
(Or get fancier and have more sanity-checking in the IHierarchy implementations.) I might have missed some other explicit casting needed also; I'm not positive that the lists can be cast directly in this way, but I think by having IHierarchy<T> inherit IHierarchy it ensures that SiteMapNode is a valid IHierarchy and thus the elements of the list work for both list types). If that list casting doesn't work, you may have to create a custom generic collection class to manage the children as both unspecified IHierarchy and as generic IHierarchy<T>.
For performance reasons you may want to add IHierarchy _CastParent; and IList<IHierarchy> _CastChildren; members and save the unspecified IHierarchy casts of these objects to avoid having to repeatedly recast them. I suggest that you always cast to the specific types (when setting from the unspecified) but you might defer casting from the specific types to the unspecified references until they are actually needed.
Now, all that, of course, is only if this extra complexity is actually helpful for what you need. It would allow you to handle the hierarchy objects as unspecified types (which might be cast more specific later, or never) or as specific or generic hierarchy types which would preserve their type knowledge for handling without casting. You would still need to cast to a specific type at some point to convert from an unspecified IHierarchy return type if you wanted to then handle them as the type-specific hierarchy.
Related
Yesterday, I was explaining C#'s generic constraints to my friends. When demonstrating the where T : CLASSNAME constraint, I whipped up something like this:
public class UnusableClass<T> where T : UnusableClass<T>
{
public static int method(T input){
return 0;
}
}
And was really surprised to see it compile. After a bit of thinking, however, I figured it was perfectly legal from the point of view of the compiler - UnusableClass<T> is as much of a class as any other that can be used in this constraint.
However, that leaves a couple of questions: how can this class ever be used? Is it possible to
Instantiate it?
Inherit from it?
Call its static method int method?
And, if yes, how?
If any of these is possible, what would the type of T be?
This approach is widely used in Trees and other Graph-like structures. Here you say to compiler, that T has API of UnusableClass. That said, you can implement TreeNode as follows:
public class TreeNode<T>
where T:TreeNode<T>
{
public T This { get { return this as T;} }
public T Parent { get; set; }
public List<T> Childrens { get; set; }
public virtual void AddChild(T child)
{
Childrens.Add(child);
child.Parent = This;
}
public virtual void SetParent(T parent)
{
parent.Childrens.Add(This);
Parent = parent;
}
}
And then use it like this:
public class BinaryTree:TreeNode<BinaryTree>
{
}
Well.
public class Implementation : UnusableClass<Implementation>
{
}
is perfectly valid, and as such makes
var unusable = new UnusableClass<Implementation>();
and
UnusableClass<Implementation>.method(new Implementation());
valid.
So, yes, it can be instantiated by supplying an inheriting type as the type parameter, and similarly with the call to the static method. It's for instance useful for tree-like structures where you want to generically specify the type of children the node has, while it being the same type itself.
If any of these is possible, what would the type of T be?
They are all possible, and you are the one who is gonna determine what is the type of T.For example let's assume there is a type that inherits from UnusableClass<T>
class Foo : UnusableClass<Foo> { }
Now you can instantiate UnusableClass<Foo> because Foo satisfies the constraint:
UnusableClass<Foo> f = new UnusableClass<Foo>();
Then the type of T become Foo and if you try to call method you need to pass an instance of Foo.
I have a class with over 100 uniquely named properties and more than 20 child-classes, sometimes in lists. Below is a greatly simplified illustration of what I mean:
public class classA
{
public String PropertyA1 { get; set; }
public int PropertyA2{get;set;}
public List<classB> myList;
public classC myClass { get; set; }
public void SetProperty(String PropertyName)
{
// Match property name to property in this class or child class.
}
}
class classB
{
public String PropertyB1 { get; set; }
public bool PropertyB2 { get; set; }
}
class classC
{
public String PropertyC1 { get; set; }
}
I would like to do two things that may or may not be possible. The first thing I need to do is iterate through every public property, including those of child classes and classes in a list, and translate the values. I know I can accomplish the parsing by serializing to xml and parsing through the results. I even have the code in place to convert to xml, as the function of the class is to build an xml object. However, I am worried that parsing through the xml might be much more expensive than accessing the properties through reflection. Can reflection be used in this manner, and would it be quicker than modifying the xml?
The other thing I would like to do is access any property passing the property name into a method. I realize I would need a separate method for accessing classes within lists, and may have to convert the list to a dictionary. The question is, would this be possible, and would the code only need to be in the parent class, or would each of the child classes need to repeat the code?
Method that will set the property with the given name:
public void SetProperty(String propertyName, object value)
{
this.GetType().GetProperty(propertyName).SetValue(this, value);
}
A few things about the implementation:
The type used is the dynamic actual type of the object, that will find members that are in derived classes (as long as the object is of the derived type of course).
The property info has no idea of what object it came from, so this must be passed in again to the SetValue() call.
The second part of your question, to iterate through a list of properties, can be solved by using GetProperties() to get all the properties of the object, including inherited ones:
var properties = this.GetType().GetProperties();
I have a class named GenericDao
internal class GenericDao<T> : IGenericDao<T> {
}
The two class of objects:
public class Empresa {
}
public class Assessoria : Empresa {
}
And i have one EmpresaDao:
public class EmpresaDao {
private GenericDao<Empresa> parent { get; set; }
public EmpresaDao() {
this.parent = new GenericDao<Empresa>();
}
}
How to instantiate the GenericDao using the subclass Assessoria? I do something like this, but not work:
public class EmpresaDao {
private GenericDao<Empresa> parent { get; set; }
public EmpresaDao(Type type) {
if (type == typeof(Assessoria)) {
this.parent = new GenericDao<Assessoria>();
} else {
this.parent = new GenericDao<Empresa>();
}
}
}
In short, you can't, really. However, you can cheat a little if you use a base interface that is not generic, or you use C# 4 and use a base interface that is generic, but with a covariant or contravariant (depending on need) type parameter. For the first case:
interface IGenericDaoBase {
}
interface IGenericDao<T> : IGenericDaoBase {
}
public class EmpresaDao {
private IGenericDaoBase parent { get; set; }
public EmpresaDao(Type type) {
// same as before
}
}
Admittedly, it might be better to rethink your design. Perhaps EmpresaDao can take a generic parameter itself, which would be used like so:
public class EmpresaDao<T> where T : Empresa {
private GenericDao<T> parent { get; set; }
public EmpresaDao() {
this.parent = new GenericDao<T>();
}
}
EDIT: In fact, the more I think about it, the more I believe this latter solution is the way to go. The type parameter in the constructor is fulfilling the same role as the type parameter on the class signature. So you won't have to change the calling code much, except to pass in a generic parameter instead of a Type object.
It is a good thing that your try don't work, you would introduce a bug if it did.
Suppose I have variables a, b both of type EmpresaDao. a is initilized with a Empresa parent and b is initialized with a Assessoria parent. Since a and b are of the same type, it should be possible to use one in place of the other everywhere. Suppose Assessoria but not Empresa has a method assess(). But you expect b.parent to be Assessoria so you want to call b.parent.assess() but you cannot call a.parent.assess() Which means a and b should not be of the same type in the first place.
The solution depends on whether you will ever call .parent.assess() :
a) If you will never call .parent.assess() within EmpresaDao class, let compile time type of the parent always be Empresa. Here is a solution :
public class EmpresaDao
{
private Empresa parent {get; set; }
public EmpresaDao(Func<Empresa> parentConstructor)
{
this.parent = parentConstructor();
}
}
static main()
{
var withEmpresaParent = new EmpresaDao(() => new Empresa());
var withAssessoriaParent = new EmpresaDao(() => new Assessoria());
..
}
b) You will sometimes call .parent.assess() within EmpresaDao class. Then you should make the EmpresaDao generic, as #siride said:
public class EmpresaDao<T> where T : Empresa
{
private T parent {get; set;}
}
However, it is still the case that you will have to make run time checks on parent before calling .parent.assess() Which means there is still something wrong in your design. But there is not enough information to decide what. Maybe .assess() method should be private and not to be called from outside (i.e. Assessoria should be a decorator on Empresa: subclass but with the same interface) Maybe "Empresa holding EmpresaDao" and "Assessoria holding EmpresaDao" should be two different classes. (implementing the same interface, probably)
Edit: Now I realize that, in my solution I mistakenly made the type of parent Empresa or Assessoria instead of GenericDao or GenericDao. I believe my main is still valid though.
This might be a simple one, but my head is refusing to wrap around that, so an outside view is always useful in that case!
I need to design an object hierarchy to implement a Parameter Registration for a patient. This will take place on a certain date and collect a number of different parameters about a patient (bloodpressure, heartrate etc). The values of those Parameter Registrations can be of different types, such as strings, integers, floats or even guids (for lookup lists).
So we have:
public class ParameterRegistration
{
public DateTime RegistrationDate { get; set; }
public IList<ParameterRegistrationValue> ParameterRegistrationValues { get; set; }
}
public class ParameterRegistrationValue
{
public Parameter Parameter { get; set; }
public RegistrationValue RegistrationValue { get; set; } // this needs to accomodate the different possible types of registrations!
}
public class Parameter
{
// some general information about Parameters
}
public class RegistrationValue<T>
{
public RegistrationValue(T value)
{
Value = value;
}
public T Value { get; private set; }
}
UPDATE: Thanks to the suggestions, the model has now morphed to the following:
public class ParameterRegistration
{
public DateTime RegistrationDate { get; set; }
public IList<ParameterRegistrationValue> ParameterRegistrationValues { get; set; }
}
public abstract class ParameterRegistrationValue()
{
public static ParameterRegistrationValue CreateParameterRegistrationValue(ParameterType type)
{
switch(type)
{
case ParameterType.Integer:
return new ParameterRegistrationValue<Int32>();
case ParameterType.String:
return new ParameterRegistrationValue<String>();
case ParameterType.Guid:
return new ParameterRegistrationValue<Guid>();
default: throw new ArgumentOutOfRangeException("Invalid ParameterType: " + type);
}
}
public Parameter Parameter { get; set; }
}
public class ParameterRegistrationValue<T> : ParameterRegistrationValue
{
public T RegistrationValue {get; set; }
}
public enum ParameterType
{
Integer,
Guid,
String
}
public class Parameter
{
public string ParameterName { get; set; }
public ParameterType ParameterType { get; set;}
}
which is indeed a bit simpler, but now I'm wondering, since the IList in ParameterRegistration points to the abstract ParameterRegistrationValue object, how will I be able to get the actual value out (since its stored on the sub-objects)?
Maybe the whole generic thing is indeed not quite the way to go after all :s
If you don't know the final set of parameter and the corresponding type of each parameter then the generics probably won't help - use object as a parameter value type.
Furthermore iterating through the list of parameters will be a pain since you'll have to examine the type of each item in order to determine how to treat the value.
What are you trying to achieve with generics ? Yes, they are cool (and going for boxing/unboxing is probably not a best idea), but in some cases you might want to use object instead (for both simplicity and flexibility).
-- Pavel
What you might want to introduce is an abstract base class for RegistrationValue<T> that is not generic, so that your ParameterRegistrationValue class can hold a non-generic reference, without needing knowledge of the type involved. Alternatively, it may be appropriate to make ParameterRegistrationValue generic also, and then add a non-generic base class for it instead (so that the list of values in ParameterRegistration can be of different types.
1st way:
public abstract class RegistrationValue
{
}
public class RegistrationValue<T> : RegistrationValue
{
public RegistrationValue(T value)
{
Value = value;
}
public T Value { get; private set; }
}
And now your code should compile.
Once you have a non-generic base class, I'd also move any members of the generic class that don't depend on the generic type parameters up into this base class. There aren't any in this example, but if we were instead modifying ParameterRegistrationValue to be generic, I'd move Parameter up into the non-generic base class (because it doesn't depend on the type parameter for RegistrationValue)
May be, you should use public RegistrationValue RegistrationValue, where T - is type, using in generic. For example, T - is String or other class or struct.
Or you should make class ParameterRegistrationValue as generic, to use generic argument in the field RegistrationValue.
I believe you want to have a collection of instances of different RegistrationValues-derived classes and be able to iterate it and for to have different type for each element. That's rather impossible.
You'll still need to cast each element to the type you know it is, because iterating the collection will return references to your base type (ParameterRegistrationValue - this one specified by IList type parameter). So it won't make any real difference from iterating over non-generic object list.
And if you can safely do that casting for each parameter (you know all the types), you probably don't need collection like this at all - it'll be better to have a class that encapsulates all the parameters in one type, so that you can call it with strong types, with IntelliSense etc. like this:
public class ParameterRegistration
{
public DateTime RegistrationDate { get; set; }
public PatientData PatientData { get; set; }
public Guid Identifier { get; set; }
// ...
}
This code compiles but looks very strange.
I have a typical and simple parent/child relationship here which is implemented using generics in a very strange way.
But I can't seem to find any other way of doing it.
class SampleObject<T> //I don't want to make this a generic but am forced to
{
//The SampleContainer this object is in
//This must be located in this base class
public SampleContainer<T> Parent { get; set; }
}
class SpecificObject : SampleObject<SpecificObject>
//SampleObject<SpecificObject> !!? This is the bizzare bit
//It seems really strange but necessary for compilation to work
{
}
//A class to contain a List of objects derived from SampleObjects
class SampleContainer<T>
{
public List<T> List;
}
class Start
{
public void Test()
{
SampleContainer<SpecificObject> container = new SampleContainer<SpecificObject>();
SpecificObject o = new SpecificObject(); //create an object
container.List.Add(o); //add it to the list
o.Parent = container; //set its parent
}
}
Can this code be simplified?
This seems to work without the type.
Is this what you were looking for?
class SampleObject //I don't want to make this a generic but am forced to
{
//The SampleContainer this object is in
//This must be located in this base class
public SampleContainer<SampleObject> Parent;//{ get; set; }
}
class SpecificObject : SampleObject
//SampleObject<SpecificObject> !!? This is the bizzare bit
//It seems really strange but necessary for compilation to work
{
}
//A class to contain a List of objects derived from SampleObjects
class SampleContainer<T>
{
public List<T> List;
}
class Start
{
public void Test()
{
SampleContainer<SampleObject> container = new SampleContainer<SampleObject>();
SpecificObject o = new SpecificObject(); //create an object
container.List.Add(o); //add it to the list
o.Parent = container; //set its parent
}
}
In the MSDN documentation, it states that:
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>
{...}
It's probably a constraint that the C# designers set up in the compiler. They require that a derived type must specify the type of the generic argument at compile time. I'm not quite sure why.
Generics can create some unwieldy class hierarchies. However, the syntax for SpecificObject : SampleObject does make sense, since you're stating that the object has a parent relationship. The only other way I could see you do this, would be to split out the hierarchy with an interface. It doesn't buy much, but it may help clarify the intent.
interface IHasParent<T>
{
T Parent { get; set; }
}
public class SpecificObject : IHasParent<SpecificObject>
{
public SpecificObject Parent { get; set; }
}
If you're concerned about how verbose your collection is, you can tame the angle brackets a bit by using:
public SpecificObjectContainer : Container<SpecificObject>
{
}