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.
Related
I have a third party DLL that returns objects like Customers, Orders, etc. I'll call them Your Entities. They do have a common IYourEntity interface so I can use that as a source constraint.
I want to create a generic conversion extension method to convert all these different third party entities to My Entities with some streamlined and more maintainable code.
....but I can't figure out how to make a generic extension method that will call the concrete extension method for the specific conversion of each class.
Putting some of the main aspects of my code below, but you can get a full fiddle to play with here.
Yes, I'm probably showing I'm a bit clueless on how to do this and maybe trying to combine different concepts. Any pointers much appreciated as I've been beating my head for a couple of days now and need a life line :)
public interface IYourEntity
{
int Id
{
get;
set;
}
}
public interface IConvertToMyEntity<TYourEntity, TMyEntity>
where TYourEntity : class, IYourEntity, new()
where TMyEntity : class, IMyEntity, new()
{
TMyEntity ToMyEntity(TYourEntity yourEntity);
}
public static class ExtensionMethods
{
private static IMyEntity ToMyEntity(this IYourEntity yourEntity)
{
return new MyEntity1();
}
public static List<IMyEntity> ToMyEntityList(this List<IYourEntity> lstYourEntities)
{
return lstYourEntities.ConvertAll(q => q.ToMyEntity());
}
}
public class YourEntity1 : IYourEntity, IConvertToMyEntity<YourEntity1, MyEntity1>
{
public int Id
{
get;
set;
}
public string YourEntityName
{
get;
set;
}
public MyEntity1 ToMyEntity(YourEntity1 yourEntity)
{
return new MyEntity1()
{Id = yourEntity.Id, MyEntityName = yourEntity.YourEntityName, CreatedOn = DateTime.UtcNow};
}
public List<MyEntity1> ToMyEntityList(List<YourEntity1> lstYourEntities)
{
return lstYourEntities.ConvertAll(q => ToMyEntity(q));
}
}
Since the classes implementing IYourEntity are from a third party and not under your control, you can't implement an own IConvertToMyEntity<T1, T2> interface upon these.
One way you can handle it is by overloads of such conversion (extension) methods.
There's no need for any generic T type arguments; the common IYourEntity interface suffices.
Suppose you have 3 classes implementing the IYourEntity interface;
e.g. YourCustomer, YourOrder and YourProduct.
These need to be converted to IMyEntity instances, of which you might have different concrete implementations;
e.g. a general MyEntity and a specific MyProduct.
For the conversion you set up an extension method targeting IYourEntity.
This extension method will be called to convert an IYourEntity to an IMyEntity in case a more specific overload of this extension method does not exist.
public static IMyEntity ToMyEntity(this IYourEntity target)
{
return new MyEntity { Id = target.Id, EntityName = "Fallback name" };
}
For the entities that require a custom conversion, you set up overloads of this extension method targeting those specific source class types.
Below are such ones for YourOrder and YourProduct (but not for YourCustomer).
public static IMyEntity ToMyEntity(this YourOrder target)
{
return new MyEntity { Id = target.Id, EntityName = target.OrderName.ToUpper() };
}
public static IMyEntity ToMyEntity(this YourProduct target)
{
return new MyProduct { Id = target.Id * 100, EntityName = target.ProductName };
}
Next, define the extension method to convert the list of IYourEntity instances to a list of IMyEntity instances. In the code below, the inbetween cast to dynamic enables that the appropriate ToMyEntity overload will be called.
Note that the ToMyEntity methods don't have to be extension methods, but it might be convenient to have these in place in case you need to convert a single instance instead of a list.
public static List<IMyEntity> ToMyEntities(this List<IYourEntity> target)
{
var myEntities = new List<IMyEntity>();
foreach (var yourEntity in target)
{
var myEntity = Extensions.ToMyEntity((dynamic)yourEntity);
myEntities.Add(myEntity);
}
return myEntities;
}
An example - .net fiddle
var yourEntities = new List<IYourEntity>()
{
new YourCustomer() { Id = 1 },
new YourOrder() { Id = 2, OrderName = "Order-2"},
new YourProduct() { Id = 3, ProductName = "Product-3"}
};
var myEnties = yourEntities.ToMyEntities();
myEnties.ForEach(o => Console.WriteLine("{0} - {1} ({2})",
o.Id, o.EntityName, o.GetType().Name
));
The output of the example above looks like below.
Notice how the YourCustomer instance was handled by the general IYourEntity conversion, whereas the YourOrder and YourProduct instances got a specific treatment.
1 - Fallback name (MyEntity)
2 - ORDER-2 (MyEntity)
300 - Product-3 (MyProduct)
You can change your extension method to this:
private static IMyEntity ToMyEntity(this IYourEntity yourEntity)
{
if (yourEntity is IConvertToMyEntity<IYourEntity, IMyEntity> convertible)
return convertible.ToMyEntity;
return new MyEntity1();
}
This will not work in most cases unless you also make your interface co- and contra-variant:
public interface IConvertToMyEntity<in TYourEntity, out TMyEntity>
where TYourEntity : class, IYourEntity, new()
where TMyEntity : class, IMyEntity, new()
{
TMyEntity ToMyEntity(TYourEntity yourEntity);
}
It is still not completely clear to me how you can make a third party class implements IConvertToMyEntity that easily. Assuming you did this only to show us your actual goal, you should be very careful with what you are trying to accomplish in the Main.
If you use a List<IYourEntity>, you can only use methods and properties defined in the interface, unless you know what you are doing with specific cast. The need for List<IYourEntity> or List<IMyEntity> limits a lot the implementation of a custom mapper between My classes and Your classes. Here a possible solution:
As I said, I did not change Your classes:
public interface IYourEntity
{
int Id
{
get;
set;
}
}
public class YourEntity1 : IYourEntity
{
public int Id
{
get;
set;
}
public string YourEntityName
{
get;
set;
}
}
Also My classes are very simple and do not contain any logic for the mapping. This is a debatable choice, but I generally prefer to keep conversion logic separated from the classes involved. This helps to maintain clean your code in case you have several conversion functions for the same pair of classes. By the way, here they are:
public interface IMyEntity
{
int Id
{
get;
set;
}
DateTime CreatedOn
{
get;
set;
}
}
public class MyEntity1 : IMyEntity
{
public int Id
{
get;
set;
}
public string MyEntityName
{
get;
set;
}
public DateTime CreatedOn
{
get;
set;
}
}
And this is how I designed the custom converter
public interface IMyEntityConverter
{
IMyEntity Convert(IYourEntity yourEntity);
}
public class MyEntity1Converter : IMyEntityConverter
{
public IMyEntity Convert(IYourEntity yourEntity)
{
var castedYourEntity = yourEntity as YourEntity1;
return new MyEntity1()
{
Id = castedYourEntity.Id,
MyEntityName = castedYourEntity.YourEntityName,
CreatedOn = DateTime.UtcNow
};
}
}
It is clear the lack of genericity, but you cannot do otherwise if you need an extension method on a List of generic My and Your classes. Also tried with covariant and contravariant interfaces but C# does not let you use them with this implementation.
Now the core of the solution: you need something that binds Your class to the My class with a custom converter, and all of this should be as more transparent as possible.
public class EntityAdapter<YourType, MyType>
where YourType : IYourEntity
where MyType : IMyEntity
{
protected YourType wrappedEntity;
protected IMyEntityConverter converter;
public EntityAdapter(YourType wrappedEntity, IMyEntityConverter converter)
{
this.wrappedEntity = wrappedEntity;
this.converter = converter;
}
public static implicit operator YourType(EntityAdapter<YourType, MyType> entityAdapter) => entityAdapter.wrappedEntity;
public static explicit operator MyType(EntityAdapter<YourType, MyType> entityAdapter) =>
(MyType) entityAdapter.converter.Convert(entityAdapter.wrappedEntity);
public MyType CastToMyEntityType()
{
return (MyType) this;
}
}
The pseudo-transparency here is given by the implicit cast to Your class. The advantage is that you can cast this EntityAdapter to an instance of a My class by calling CastToMyEntityType or the explicit operator overload.
The painful part is with the extension methods:
public static class EntityAdapterExtensions
{
public static List<IMyEntity> ToIMyEntityList(this List<EntityAdapter<IYourEntity, IMyEntity>> lstEntityAdapters)
{
return lstEntityAdapters.ConvertAll(e => e.CastToMyEntityType());
}
public static List<EntityAdapter<IYourEntity, IMyEntity>> ToEntityAdapterList(this List<IYourEntity> lstYourEntities)
{
return lstYourEntities.Select(e =>
{
switch (e)
{
case YourEntity1 yourEntity1:
return new EntityAdapter<IYourEntity, IMyEntity>(yourEntity1, new MyEntity1Converter());
default:
throw new NotSupportedException("You forgot to map " + e.GetType());
}
}).ToList();
}
}
The first one is pretty straightforward to understand, but the second one is definitely something that require maintenance. I gave up on generics for the reasons already explained, so the only thing left to do is to create the EntityAdapters starting from the actual entity types.
Here is the fiddle
This may be a little controversial but maybe a different way is better?
Firstly, and this is more for my sake, I would suggest more easily understandable terminology so instead of 'your' and 'my' I would use 'source' and 'dest'.
Secondly I wonder if the generics route is necessary? I'm assuming (and I may be wrong) that for each of the classes you have coming from your third-party assembly, you have a specific class for it to be converted to. So maybe this could be achieved much more easily with a constructor override in your destination class.
// third party class example
public class SourceClass
{
public int Id { get; set; }
public string Name { get; set; }
}
// the destination class in your project
public class DestClass
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedOn { get; set; }
// default constructor
public DestClass()
{
}
// conversion constructor
public DestClass(SourceClass source)
{
Id = source.Id;
Name = source.Name;
CreatedOn = DateTime.UtcNow;
}
}
This way you convert a single instance using:
// source being an instance of the third-party class
DestClass myInstance = new DestClass(source);
And you can convert a list with LINQ:
// source list is IList<SourceClass>
IList<DestClass> myList = sourceList.Select(s => new DestClass(s)).ToList();
If you wanted to you could implement extensions for your conversions. This again would not be generic as you'll need one for each class pairing but as it's an alternative to writing a converter class for each, it will be overall less code.
public static class SourceClassExtensions
{
public static DestClass ToDest(this SourceClass source)
=> new DestClass(source);
public static IList<DestClass> ToDest(this IList<SourceClass> source)
=> source.Select(s => new DestClass(s)).ToList();
}
If you still want something generic then you'll want a converter for each class pair, implementing a suitable interface. Then I'd recommend a converter factory class where you'll need to register the specific converters either into a dictionary in the class or via dependency injection. I can go into this further if you'd prefer but I think it would be more complicated.
sorry for writing here its not an actual answer,
there is no option for generically to do this
you have to write for every entity
public interface IConvertToMyEntity<TYourEntity, TMyEntity>
where TYourEntity : class, IYourEntity, new()
where TMyEntity : class, IMyEntity, new()
{
TMyEntity ToMyEntity(TYourEntity yourEntity);
}
I saw this code from your question.
It depends on what you want to do after transformation
you should use data mapper
public class MapProfile : Profile
{
public MapProfile()
{
CreateMap<TYourEntity , TMyEntity >();
CreateMap<TMyEntity , TYourEntity >();
}
}
I am struggling with an issue related with conversion between generic, possibly it's an easy one.
Basically I want to create a list of base class and add into it multiple classes.
public interface IQueryEngineDependency
{
public IEnumerable<QueryDependencyDetail> GetDependencies<>();
}
public abstract class QueryDependencyDetail
{
public int Order { get; set; }
}
public class QueryDependencyDetail<TEntity, TKey> : QueryDependencyDetail
where TEntity : BaseEntity<TKey>
{
public virtual Func<TEntity, object> Key { get; set; }
public IQueryable<TEntity> Data { get; set; }
public Func<TEntity, object> JoinKey { get; set; }
public Expression<Func<TEntity, bool>> WhereClause { get; set; }
}
Problem
I have a class, per example, that implements the interface shown above but I am figuring it out the right way to implement this.
public class TestQueryDependency : IQueryEngineDependency
{
public IEnumerable<QueryDependencyDetail> GetDependencies()
{
var dependencies = new List<QueryDependencyDetail>
{
new QueryDependencyDetail<Tasks, long>
{
Order = 1,
Data = null // just to simplify
}
};
return dependencies;
}
}
If I call the method GetDependencies somewhere in the code how can I make the downcasting to access the generic type fields? I mean I will get the instances of QueryDependencyDetail type. Then is it possible to convert it to QueryDependencyDetail<TEntity, TKey>?
Or is there another way to do this?
EDIT
var testDep = new TestQueryDependency();
var dependencies = testDep.GetDependencies();
Remember that dependencies may have up to 20 different instances in my particular implementation.
How can I access the Data field, per example? (Just a simple scenario)
var first = dependencies.FirstOrDefault()?.Data; ?????
I will need this to perform dynamic queries using LINQ.
Thanks in advance.
I am not sure what you are trying to accomplish.
What if you put the generic arguments on the engine interface?
public interface IQueryEngineDependency<TEntity,TKey> where TEntity : BaseEntity<TKey> {
public IEnumerable<QueryDependencyDetail<TEntity,TKey>> GetDependencies();
}
Then you can create a test engine:
public class TestQueryDependency : IQueryEngineDependency<Tasks,long> {
public IEnumerable<QueryDependencyDetail<Tasks,long >> GetDependencies() {
var dependencies = new[] {
new QueryDependencyDetail<Tasks, long> {
Order = 1,
Data = null // just to simplify
}
};
return dependencies;
}
}
You should be able to just cast it, i.e. (QueryDependencyDetail<TEntity, TKey>) myObject
However, you must make sure that the type actually match the real object. Lets take a simplified example:
public class A { }
public class B<T> : A { }
public static B<T> Test<T>(A a) => (B<T>)a;
and
var a = new B<int>();
var b1 = Test<int>(a); // works since a is of type of B<int>
var b2 = Test<string>(a); // Will throw invalid cast exception since a is not of type B<string>
You can also test the type:
if(a is B<int> b)
The problem here is that you have to know the actual type of the object. You cannot just cast a to B<T> without somewhere declaring what T actually is.
The solution I have used for these kind of problems is to avoid anything that needs to know the generic type. Make sure the interface or base class contain all methods you ever need when interacting with the object. This can be a bit complicated when multiple classes are involved, but it is usually possible.
edit:
A third option could be to use reflection. This can allow you to inspect the actual types of the generic type parameters. It may allow for things like creating another object with the same generic type parameter. The downside is that using reflection can be quite cumbersome and may be error prone and slow.
The following code is a simplified version what I have:
public class Message
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
}
public class ExtendedMessage<TExtension> : Message
{
public TExtension Extension { get; set; }
}
public class Processor<T> where T : Message
{
public void Process(T message)
{
}
}
I will have many types that inherit from either Message or ExtendedMessage. I would like to be able to use Processor to process those that inherit from ExtendedMessage<> as well as Message. However that involves manipulating the Extension property for those that have it.
In order to do that it seems I would need to cast the message parameter to the process method to ExtendedMessage<>, if it is of that type. I have tried to do that using the following:
if (IsInstanceOfGenericType(typeof(JsonModel<>), model))
{
var dataType = message.GetType().GetGenericArguments()[0];
Type type = typeof(ExtendedMessage<>).MakeGenericType(dataType);
var extendedMsg = Activator.CreateInstance(type);
//Processing using extendedMsg.Extension
}
Where IsInstanceOfGenericType is from this answer: Testing if object is of generic type in C#
However that does not work, obviously the property is not available. Is it possible to process both types in the same method? Am I going about this the right way in the first place? I would like to avoid extending Processor to create a separate ExtendedMessageProcessor if possible. Thanks.
The easy-but-wrong answer would be to use dynamics:
var extension = ((dynamic)message).Extension
A better answer would be to have your extensions inherit from a base
public class ExtendedMessage : Message
{
public ExtensionBase Extension { get; set; }
}
public abstract class ExtensionBase
{
}
...
var extendedMessage = message as ExtendedMessage;
if (extendedMessage != null)
{
//process
}
If something like this isn't possible and you're stuck with reflection, you don't want to create a new instance of the message. You already have the message and it has the properties on it you need. You should be using Type.GetProperties() and Type.GetMethods().
I am trying to convert Base class to derived class object. See below code, I am having the issue when I converting. It is basic thing, but struggling.
[HttpGet]
[Route("/Edit/{Id}")]
public ActionResult Edit(int Id)
{
List<ClassA> Data = Ctx.GetClassAFromId(Id);
// Now Here I want convert ABC List<ClassA> to XyZ List<ClassA>
//How to do that?
return View(DataXYZ);
}
Model generate by EF
namespace ABC
{
public partial class ClassA
{
public string First_name { get; set; }
public string Last_Name { get; set; }
}
}
Project model
namespace XYZ
{
[MetadataType(typeof(ClassAMetadata))]
public partial class ClassA:ABC.ClassA
{
}
public class ClassAMetadata
{
[DisplayName(#"First Name")]
[Required]
public string First_name { get; set; }
[DisplayName(#"Last Name")]
[Required]
public string Last_Name { get; set; }
}
}
How Can convert ABC.ClassA to XYZ.ClassA?
Edit:
we are working on i18n project. So we need to display each text in different languages. But our EF project is in different Namespace and web project is in different Namespace. that is the reason I deriving from base class
You can't convert List<BaseClass> to List<DerivedClass>
What you can do is used linq:
listABC.Cast<XYZ.ClassA>.ToList()
But lookout - it is O(n) procedure
Even though their names are alike, they are completely different classes. It'd be just the same as if you called them Foo and Bar
You'll need a method that converts these objects. It takes a Foo object as parameter, then returns an equivalent Bar object
public Bar Foo_To_Bar(Foo myFoo)
{
return new Bar() { Prop1 = myFoo.Prop1, Prop2 = myFoo.Prop2 };
}
Something like that. You'll probably also need a method that goes the other way around if you want to convert in both directions.
Note: If the classes have properties with the same name, I suggest you look into Automapper. It automates much of the boring work for you.
Edit
Apparently, your Foo inherits from Bar. That complicates things a bit more. I'll rework this answer when I get the time.
I don't see a use case for having your ViewModel (XYZ.ClassA) derive from your base entity (ABC.ClassA). Can you explain why this is needed? I think you're misusing inheritance here.
Generally speaking, you'd want your XYZ.ClassA to have a property of type ABC.ClassA (or any IEnumerable<ABC.ClassA> variation), not inherit from it.
Can you please confirm if this is an actual requirement, or can be part of the issue and is allowed to change if it fixes your problem?
EDIT - based on the fact that one object is inherited from the other, see C#/.NET Little Wonders: Use Cast() and OfType() to Change Sequence Type
Couple of options:
1.
namespace ABC
{
public partial class ClassA
{
public ClassA(XYZ.ClassA classToConvert)
{
this.First_name = classToConvert.First_name,
this.Last_Name = classToConvert.Last_Name
}
public string First_name { get; set; }
public string Last_Name { get; set; }
}
}
Use it singularly:
var newClassA = new ABC.ClassA((XYZ.ClassA)classA)
Do it in a list:
List<ABC.ClassA> newClassAList = classAList.Select(p => new ABC.ClassA((XYZ.ClassA)p).ToList();
Or do it in a list without the above constructor and using an object initaliser
List<ABC.ClassA> newClassAList = classAList.Select(p => new ABC.ClassA{First_name = p.First_name, Last_Name = p.Last_Name}.ToList();
As others have mentioned Use AutoMapper.
Use Nuget and add AutoMapper to your project (and some initalisation code)
Create your Map:
Mapper.CreateMap<XYZ.ClassA, ABC.ClassA>();
Map your objects:
var myABCClassA= Mapper.Map<XYZ.ClassA, ABC.ClassA>(myXYZClassA);
As long as your property names on both classes match thats all the code you need
I created this today
public static void Map<T1, T2>(this T1 obj1, T2 obj2) where T1 : class where T2 : class
{
IEnumerable<(PropertyInfo p1, PropertyInfo p2)> properties = typeof(T1).GetProperties()
.Join(typeof(T2).GetProperties(), o => o.Name, t => t.Name, (o, t) => (o, t));
foreach((PropertyInfo p1, PropertyInfo p2) in properties)
{
if (p1.CanWrite && p1.PropertyType == p2.PropertyType)
{
p1.SetValue(obj1, p2.GetValue(obj2));
}
}
}
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; }
// ...
}