C# class design with Generic structure - c#

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; }
// ...
}

Related

Convert instance method to class method C#

I have a instance method that creates a new instance of a class. I would like for this to be a class method. The problem is that I get an error when trying to call GetType() in the static method. Is it possible to convert this method to a static method ?
error
An object reference is required for the non-static field, method or property 'object.GetType()'.
Customer.New
public object WithAttributes(ExpandoObject valueObject)
{
var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.GetSetMethod() != null);
var self = Activator.CreateInstance(GetType());
var values = (IDictionary<string, object>)valueObject;
foreach (var property in properties)
{
if (values.Keys.Contains(property.Name))
{
var val = values[property.Name];
property.SetValue(self, values[property.Name]);
}
}
return self;
}
BaseEntity.cs
public class BaseEntity
{
public Int64 Id { get; set; }
public DateTime AddedDate { get; set; }
public DateTime ModifiedDate { get; set; }
public string IPAddress { get; set; }
public object WithAttributes(ExpandoObject valueObject)
{
// Same code as above
}
}
Customer.cs
public class Customer : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string MobileNo { get; set; }
}
Desired Usage
dynamic attributes = new ExpandoObject();
attributes.FirstName = "James";
attributes.LastName = "Jones";
var customer = Customer.WithAttributes(attributes);
Well, Unfortunately for you it is impossible to get the implementing type from the base abstract type's static method. According to reed copsey's answer here and to Jon Skeet's answer there. As you can see in Jon's answer, the c# compiler associate the static method to the type it was declared in, even if it was executed from a deriving type.
This means that your abstract class must be aware of the type that implements it, or at least this method must be aware of the type where it's called from.
One way to do it is to create the WithAttributes as a generic method:
public static T WithAttributes<T>((ExpandoObject valueObject)) where T: BaseEntity, new
{
// Here you can use typeOf(T)
}
This have some advantages (for instance, you can simply write var self = new T() instead of using Activator.CreateInstance(), and you don't need to return an object but the actual type.
However, you can't force the code that's calling this method to pass the correct type - nothing is stopping you from doing something like this:
var customer = Customer.WithAttributes<SomeOtherBaseEntityDerivedClass>(attributes);
Rob Leclerc's answer here Is another attempt to solve this using generics, Only this is creating the entire abstract class as a generic class, so instead of public class BaseEntity you will have
public class BaseEntity<TChild>
and then you can use typeOf(TChild).
This has the same disadvantage as my suggestion (you can do public class Customer : BaseEntity<SomeOtherType> just as easily).
Daniel A. White Answered his own question by taking the type as a parameter to the static method in the abstract class:
public static object WithAttributes(Type type, ExpandoObject valueObject)
Again, it has the same drawbacks as using the generic approach, but it also have the drawbacks of your approach - it must return object and you must use Activator.CreateInstance.
To conclude - What you are asking for can't be done safely.
I will not recommend using any of these approaches for a public API, but If you know your team are the only programmers that will inherit the BaseEntity, I would probably go with the generic approach, as long as you make sure everybody knows the compiler can't protect them from using the wrong type parameter.

Returning Unknown Type Without Generics

In my abstract base class AbstractType, I have an abstract auto-implemented property Value of unknown type. All my derived classes implement this property with their own types, such string or double. Normally, I know you would just make it AbstractType<T> and have the property be T Value { ... }. However, I don't have the ability to use generics in this case. In AbstractType, I'm trying to implement a method that returns a new derived class from AbstractType, so if I use generics, the caller has to know the type. If I make Value type object, then the caller has to wrap the object to the correct type - very inconvenient type/instance checking.
Here's what my class structure looks like (the method is simplified for the sake of demonstration):
abstract class AbstractType
{
public abstract ??? Value { get; set; }
AbstractType FromValue(int i)
{
if (i == 0)
return new NumberType();
else
return new StringType();
}
}
class NumberType : AbstractType
{
public override double Value { get; set; }
}
class StringType : AbstractType
{
public override string Value { get; set; }
}
Is there any way to do this without using generics?

return a class containing generic List

I'm trying to construct a class in c# (5.0) that I can use as a base class and it contains a List, but List could be 2 different types. I want to do the following:
public class BaseC
{
string header { get; set; }
List<object> recs { get; set; }
}
public class derive1: BaseC
{
List<myclassA> recs;
}
public class derive2: BaseC
{
List<myclassB> recs;
}
and importantly what I want to do is return the derived classes from a method in another class:
public BaseC PopulateMyDerivedClass()
{
BaseC b = new BaseC();
b.header = "stuff";
b.recs = FileHelperEngine<myclassB> fhe.ReadStringAsList(x);
}
the main point is that method PopulateMyDerivedClass really does the exact same thing for both derive1 and derive2, just that it returns a different type of list.
I think I need generics. But is that at the base class level and also is PopulateMyDerivedClass then supposed to return a generic? I think that perhaps I am not dealing with polymorhpism, but as you can guess I am new to generics, so struggling.
I think what you want is to make BaseC a generic class and specify the generic when defining the derived classes:
public class BaseC<T>
{
//...
virtual List<T> Recs { get; set; }
}
public class Derived1 : Base<MyClassA>
{
override List<MyClassA> Recs { get; set; }
}
Good point by Alexei Levenkov:
Usual note: DerivedX classes in this case will not have common parent unlike original sample. One may need to add more layer of classes (as non-generic parent of BaseC) or use an interface if DerivedX need to be treated as having common parent/interface.
I get the feeling that your code design could use some rethinking. For one, typically when we talk about "polymorphism", we are usually talking about polymorphic behaviors (methods), rather than members. I think you might want to consider two classes that implement an interface that does all the things you want each class to do (parses data into its own type of list and acts on it as you need it to).
Nevertheless, without getting way into the details of your code, I think something like this might be what you were trying to achieve:
public class BaseC<T>
{
string header { get; set; }
public List<T> recs {get;set;}
}
and
public BaseC<T> PopulateClass<T>()
{
var b = new BaseC<T>();
b.recs = new List<T>();
T first = (T)Convert.ChangeType("1", typeof(T));
b.recs.Add(first);
return b;
}
And to check our sanity:
BaseC<String> d1 = PopulateClass<String>();
System.Diagnostics.Debug.Print(d1.recs.First().ToString());
System.Diagnostics.Debug.Print(d1.recs.First().GetType().ToString());
BaseC<int> d2 = PopulateClass<int>();
System.Diagnostics.Debug.Print(d2.recs.First().ToString());
System.Diagnostics.Debug.Print(d2.recs.First().GetType().ToString());
prints
1
System.String
1
System.Int32

Can C# constraints be used without a base type?

I have some classes with common properties, however, I cannot make them derive from a base type (LINQ-to-SQL limitations).
I would like to treat them as if they had a base type, but not by using Reflection (performance is critical).
For example:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
}
public class Vehicle
{
public int Id { get; set; }
public string Label { get; set; }
}
In this case I would be happy if I had the Id property available, regardless of the type I'm holding.
Is there any way in C# to to something similar to this:
public static int GetId<T>(T entity) where T // has an int property 'Id'
{
return entity.Id;
}
I guess I could have used dynamic, however, I'm looking for a way to restrict the code in compile time from using this method for an object that has no Id property.
You can use interfaces:
public interface IHasId
{
int Id { get; }
}
public class User : IHasId { ... }
public class Vehicle : IHasId { ... }
public static int GetId<T>(T entity) where T : IHasId
{
return entity.Id;
}
However, if you are not able to modify the classes to add the interface, you won't be able to do this. No compile-time checks will verify that a property exists on T. You'd have to use reflection - which is slow and obviously not ideal.
There is no way to guarantee a type has a given member without constraining to a common base type or interface. One way to work around this limitation is to use a lambda to access the value
public static int Use<T>(T value, Func<T, int> getIdFunc) {
int id = getIdFunc(value);
...
}
Use(new User(), u => u.Id);
Use(new Vehicle(), v => v.Id);
You can create an interface with the common properties and make your classes implement it:
public interface IEntity
{
int Id { get; set; }
}
public class User : IEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
}
public class Vehicle : IEntity
{
public int Id { get; set; }
public string Label { get; set; }
}
public static int GetId<T>(T entity) where T : IEntity
{
return entity.Id;
}
You could simplify GetId like this:
public static int GetId(IEntity entity)
{
return entity.Id;
}
The other answers mentioning the interface approach are certainly good, but I want to tailor the response to your situation involving Linq-to-SQL.
But first, to address the question title as asked
Can C# constraints be used without a base type?
Generally, the answer is no. Specifically, you can use struct, class, or new() as constraints, and those are not technically base types, and they do give some guidance on how the type can be used. That doesn't quite rise to the level of what you wish to do, which is to limit a method to types that have a certain property. For that, you will need to constrain to a specific interface or base class.
For your specific use case, you mention Linq-to-SQL. If you are working from models that are generated for you, then you should have options to modify those classes without modifying the generated model class files directly.
You probably have something like
// code generated by tool
// Customer.cs
public partial class Customer // : EntityBaseClasses, interfaces, etc
{
public int ID
{
get { /* implementation */ }
set { /* implementation */ }
}
}
And other similar files for things such as Accounts or Orders or things of that nature. If you are writing code that wishes to take advantage of the commonly available ID property, you can take utilize the partial in the partial class to define a second class file to introduce a common interface type to these models.
public interface IIdentifiableEntity
{
int ID { get; }
}
And the beauty here is that using it is easy, because the implementation already exists in your generated models. You just have to declare it, and you can declare it in another file.
public partial class Customer : IIdentifiableEntity { }
public partial class Account : IIdentifiableEntity { }
// etc.
This approach has proven valuable for me when using a repository pattern, and wishing to define a general GetById method without having to repeat the same boilerplate in repository after repository. I can constrain the method/class to the interface, and get GetById for "free."
Either you need to make both classes implement an interface with the properties you need, and use that in the generic constraint, or you write separate methods for each type. That's the only way you'll get compile-time safety.

C# Generic Inheritance Issue with Base Library

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.

Categories

Resources