I want to pass a list/dictionary of generic parameter (that can be different types in the same collection) to a method in a modular application.
I hope my code can explain it better.
The interfaces:
public interface IField
{ }
public interface IField<T> : IField
{
T Value { get; }
}
The implemented class:
public class Field<T> : IField<T>
{
public Field(T value)
{
Value = value;
}
public T Value { get; set; }
}
Now I can create a Dictionary with my parameters and call a method that is implemented in a different assembly not referenced (I get it using reflection):
static void Main(string[] args)
{
var dicFields = new Dictionary<string, IField>();
dicFields.Add("param1", new Field<string>("Hello"));
dicFields.Add("param2", new Field<int>(15));
MyMethod(dicFields);
}
Now, in 'MyMethod', I want to get the value for a specific parameter in the dictionary:
public void MyMethod(IDictionary<string, IField> parameters)
{
var param2 = parameters["param2"];
}
The problem is that 'param2' has not the property Value (generic type) because I used the IField interface to define the dictionary elements and in 'MyMethod' we can't know the right implementation of the parameter.
Any suggestion to achieve my goal?
Generics do not work this way.
To get the Generic Types, you need to use the IField<T> interface in your dictionary and your method.
However, you aren't going to be able to mix types because when you create an instance of a class you IField will be restricted to only T:
public interface IField
{
}
public interface IField<T> : IField
{
T Value { get; }
}
public class Field<T> : IField<T>
{
public Field(T value)
{
Value = value;
}
public T Value { get; set; }
}
public void Generic()
{
var dicFields = new Dictionary<string, IField<string>>();
dicFields.Add("param1", new Field<string>("Hello"));
dicFields.Add("param2", new Field<string>("Hello"));
MyMethod<String>(dicFields);
}
public void MyMethod<T>(IDictionary<string, IField<T>> parameters)
{
var param2 = parameters["param2"].Value;
}
If you wanted to mix types you would need to use IField which will require you to box and unbox your types:
public interface IField
{
}
public interface IField<T> : IField
{
T Value { get; }
}
public class Field<T> : IField<T>
{
public Field(T value)
{
Value = value;
}
public T Value { get; set; }
}
public void Generic()
{
var dicFields = new Dictionary<string, IField<object>>();
dicFields.Add("param1", new Field<object>("Hello"));
dicFields.Add("param2", new Field<object>(2));
MyMethod<object>(dicFields);
}
public void MyMethod<T>(IDictionary<string, IField<T>> parameters)
{
var param2 = parameters["param2"].Value;
}
While it is considered bad practice, you could use a Dictionary<string, Dynamic>
Dictionary<string, dynamic> dict = new Dictionary<string, dynamic>();
dict.Add("value1", "a");
dict.Add("value2", 2);
dict.Add("value3", 3);
int result = dict["value2"] + dict["value3"];
One way to manage what you're trying to do is to add access methods to IField that will allow you to get an object value and the type.
public interface IField
{
object GetValue { get; }
Type GetValueType();
}
Related
I have a VO class that contains several variables incl. a variable that can be of different types and to prevent casting later on I wonder if I can make that class generic.
public class InputVO<T>
{
public bool isEnabled;
public T value;
}
Then I want to create an array of InputVOs and a method to get a typed InputVO...
public InputVO[] Inputs { get; private set; }
public InputVO GetInput(InputType type)
{
return Inputs[(int)type];
}
How do I go about defining the array and the GetInput method so that they work with the generic InputVO? (The InputType type argument is an enum. Shouldn't really matter here, I think).
Generic type parameters are fixed at compile-time.
Whenever you use InputVO, that type parameter needs to be filled in.
public InputVO<T1>[] Inputs { get; private set; }
But what you seem to want is different InputVO objects for each datatype, and to be able to retrieve them by type at runtime:
// Base class for all InputVOs
public abstract InputVOBase
{
public bool isEnabled;
}
// InputVO for a specific data-type
public class InputVO<T> : InputVOBase
{
public T Value;
}
Now you can use a dictionary from Type to InputVOBase.
// One InputVO per datatype
public Dictionary<Type, InputVOBase> AllInputs { get; private set; }
// Return the VO for type T, or null
public InputVO<T> GetInput<T>()
{
InputVOBase vo = AllInputs[typeof(T)];
return (vo as InputVO<T>);
}
You cannot create an array of a generic class without specifying the type. However, as you have control over the base type, you can make that implement a non generic interface and have a collection of that instead:
//Empty interface
public interface IInputVO { }
//Your generic class now implements the interface
public class InputVO<T> : IInputVO
{
public bool isEnabled { get; set; }
public T Value { get; set; }
}
So now your array is of the interface type IInputVO:
IInputVO[] inputs =
{
new InputVO<int>(),
new InputVO<string>(),
new InputVO<SomeClass>(),
};
Cleaned up solution a bit. Mainly you need to collect your values in a dictionary.
void Main()
{
var a = new InputVO<string> { Value = "test" };
var b = new InputVO<int> { Value = 5 };
Inputs.Add(typeof(string), a);
Inputs.Add(typeof(int), b);
var x = GetInput<string>();
Console.WriteLine(x.Value);
var y = GetInput<int>();
Console.WriteLine(y.Value);
}
public abstract class InputVOBase
{
public bool isEnabled;
}
public class InputVO<T> : InputVOBase
{
public T Value;
}
public Dictionary<Type, InputVOBase> Inputs = new Dictionary<Type, InputVOBase>();
public InputVO<T> GetInput<T>()
{
return Inputs[typeof(T)] as InputVO<T>;
}
Thanks for the tips anyone! Phew, since there's no way getting around casting and I only need to regard a couple of types I think all the generics-based solutions are a bit overkill in my case. So I simply added casted getters to my VO ...
public class InputVO
{
public bool isEnabled;
public bool isValid;
public InputType type;
public object value;
public int IntValue { get { return (int)value; } }
public float FloatValue { get { return (float)value; } }
public bool BoolValue { get { return (bool)value; } }
public Vector2 Vector2Value { get { return (Vector2) value; } }
public Vector3 Vector3Value { get { return (Vector3)value; } }
}
Consider the following classes and interfaces:
interface INameable
{
string Name { get; }
}
interface IRepository<T>
{
void Add(T obj);
IEnumerable<T> Values { get; }
}
class Person : INameable
{
public string Name { get; set; }
public int Age { get; set; }
}
class Car : INameable
{
public string Name { get; set; }
public string Model { get; set; }
}
I now would like to create a Repository class that implements both IRepository<Car> and IRepository<Person>. Here is a sample implementation:
class Repository : IRepository<Car>, IRepository<Person>
{
Dictionary<string, object> values = new Dictionary<string, object>();
void AddValue(INameable o)
{
values.Add(o.Name, o);
}
IEnumerable<T> ValuesOfType<T>()
{
return values.Values.OfType<T>();
}
void IRepository<Car>.Add(Car obj)
{
AddValue(obj);
}
void IRepository<Person>.Add(Person obj)
{
AddValue(obj);
}
IEnumerable<Car> IRepository<Car>.Values
{
get { return ValuesOfType<Car>(); }
}
IEnumerable<Person> IRepository<Person>.Values
{
get { return ValuesOfType<Person>(); }
}
}
This works exactly as expected. However, it is very repetitive; the code for the implementation of IRepository<Person> and IRepository<Car> is nearly exactly the same.
What I would like to do is implement IRepository for all T where T is a INameable. I tried this:
class Repository2 : IRepository<Car>, IRepository<Person>
{
// same as before
Dictionary<string, object> values = new Dictionary<string, object>();
void AddValue(INameable o)
{
values.Add(o.Name, o);
}
IEnumerable<T> ValuesOfType<T>()
{
return values.Values.OfType<T>();
}
// using generics to implement both the interfaces
void Add<T>(T obj) where T : INameable
{
AddValue(obj);
}
void Values<T>() where T : INameable
{
return ValuesOfType<T>();
}
}
However I get errors like:
ConsoleApp.Repository2' does not implement interface member 'ConsoleApp.IRepository<ConsoleApp.Car>.Add(ConsoleApp.Car)'
I'm not sure why the Add<T> and Vales<T> methods aren't being matched - both T's can be set to Person and Car, and then they would exactly match the method type needed.
Finally, I tried:
class Repository3 : IRepository<T> where T is INameable {... }
However, I get an error "Constraints are not allowed on non-generic declarations".
What is the best way of solving this problem?
Note that I am doing this as a method to simply access to a DbContext class (which has references to every table in the application), so instead of passing the full database to each controller, I only pass the data that is needed. I was doing this to better separate the database from the rest of the app, and to improve testability. If there is a better way of doing this that could also help.
You could have an abstract class with the implementation and then just inherit it for specific types.
public interface INameable
{
string Name { get; }
}
public interface IRepository<T>
{
void Add( T obj );
IEnumerable<T> Values { get; }
}
public class Person : INameable
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Car : INameable
{
public string Name { get; set; }
public string Model { get; set; }
}
public abstract class AbstractRepository<T> : IRepository<T>
where T : INameable
{
// same as before
Dictionary<string, object> values = new Dictionary<string, object>();
void AddValue( INameable o )
{
values.Add( o.Name, o );
}
IEnumerable<T> ValuesOfType<T>()
{
return values.Values.OfType<T>();
}
// using generics to implement both the interfaces
public void Add( T obj )
{
AddValue( obj );
}
public IEnumerable<T> Values
{
get
{
return ValuesOfType<T>();
}
}
}
public class CarRepository : AbstractRepository<Car> { }
public class PersonRepository : AbstractRepository<Person> { }
In my experience, it is much easier that all the entities, that are to be added to some repository, conform to some interface, say IBaseObject:
interface IRepository
{
void Add(IBaseObject obj);
IEnumerable<IBaseObject> Values { get; }
}
This generally ends up being a good solution because in IBaseObject you could have an identifier so you know when to add or an update an existing record.
update:
Another approach is to use the following pattern, again still relying on IBaseObject:
interface IRepository
{
void Add(T obj) where T : IBaseObject;
IEnumerable<T> GetValues() where T : IBaseObject;
}
I think, you should create class that creates repositories. Something like this:
class Repository<T> : IRepository<T>
where T : INameable
{
Dictionary<string, T> values = new Dictionary<string, T>();
void AddValue(T o)
{
values.Add(o.Name, o);
}
public void Add(T obj)
{
AddValue(obj);
}
public IEnumerable<T> Values
{
get { return values.Values; }
}
}
class UnitOfWork
{
private readonly Dictionary<Type, object> _repositories = new Dictionary<Type, object>();
public IRepository<T> GetRepository<T>()
where T : INameable
{
object repository;
if (!_repositories.TryGetValue(typeof (T), out repository))
{
repository = new Repository<T>();
_repositories[typeof (T)] = repository;
}
return (IRepository<T>)repository;
}
}
And use it like that:
var unitOfWork = new UnitOfWork();
unitOfWork.GetRepository<Car>().Add(new Car {Name = "Audi"});
unitOfWork.GetRepository<Car>().Add(new Car { Name = "BMW" });
foreach (var car in unitOfWork.GetRepository<Car>().Values)
Console.WriteLine(car.Name);
I have an interface
public interface IImageFilter<TIn, TOut>
{
// Properties
TIn Input { get; set; }
string Name { get; set; }
Guid Guid { get; set; }
TOut Process(TIn frame);
}
and I needed an observable collection of objects that implement the interface.
private ObservableCollection<IImageFilter<T, U>> _imageFilters;
the object that i pass to the collection can be
IImageFilter<string, string>
IImageFilter<string, int>
IImageFilter<int, double>
How do it declare the _imageFilters? what's the T? or U?
Closes you can get to it is
private ObservableCollection<object> _imageFilters;
If you have control over the IImageFilter, you can do something like:
public interface IImageFilterBase {
object Input { get; set; }
string Name { get; set; }
Guid Guid { get; set; }
object Process(object frame);
}
public interface IImageFilter<TIn, TOut> : IImageFilterBase {
// Properties
new TIn Input { get; set; }
TOut Process(TIn frame);
}
public abstract class FilterBase<TIn, TOut> : IImageFilter<TIn, TOut> {
public TIn Input { get; set; }
public abstract TOut Process(TIn frame);
object IImageFilterBase.Input {
get { return this.Input; }
set { this.Input = (TIn)value; }
}
public string Name { get;set;}
public Guid Guid { get; set; }
public object Process(object frame) {
return this.Process((TIn)frame);
}
}
// test class
public class StringToInt32 : FilterBase<string, int> {
public override int Process(string frame) {
return Convert.ToInt32(frame);
}
}
and declare the collection like
private ObservableCollection<IImageFilterBase> _imageFilters;
Not really impossible, Another approach is to use Covariant Generic type. But it will require some change in your interface.
Your Interface:
internal interface IImageFilter<out I, out O>
{
I Input { get; }
O Process();
}
Interface Implementation
public class ImageFilter : IImageFilter<string, string>
{
public string Input { get; private set; }
public ImageFilter(string input)
{
Input = input;
}
public string Process()
{
return Input.ToUpper();
}
}
Usage:
List<IImageFilter<object, object>> filters= new List<IImageFilter<object, object>>();
ImageFilter filter= new ImageFilter("something");
filters.Add(filter);
The designs of generic interfaces within the Framework, as well as the design of delegates (which provided quasi-generic behavior before real generics were available), require that all generic type parameters be replaced with closed-form generics. It is possible to design interfaces for use with open-form generics, but the interfaces within the framework are not suitable.
As a simple example, suppose one wishes to have an interface which is somewhat analogous to Action<T>, but instead of taking a parameter of type T, it will accept one parameter of any type which satisfies two constraints, TC1 and TC2. One could define it as:
interface ActStatisfyingConstraints<in TC1, in TC2>
{
void Invoke<T>(ref T param) where T:TC1,TC2;
}
Note that an implementation of that interface would be able to pass a T as a generic parameter to any other method which constrained it to TC1 and TC2, even if there is no single class which satisfies both constraints and also serves as a base class for all objects that do.
In the case of your observable collection, you should define an observer interface which includes notification methods like those above. The event-subscribe method would keep a list of references to the observers; adding something to the collection should then call the generic notify-of-added-item method on the each item in the list.
This sample:
public static void createDictionary<T>(IEnumerable<T> myRecords)
where T: T.ID // Wont Compile
{
IDictionary<int, T> dicionario = myRecords.ToDictionary(r => r.ID);
foreach (var item in dicionario)
{
Console.WriteLine("Key = {0}",item.Key);
Type thisType = item.Value.GetType();
StringBuilder sb = new StringBuilder();
foreach (var itemField in thisType.GetProperties())
{
sb.AppendLine(string.Format("{0} = {1}", itemField.Name, itemField.GetValue(item.Value, null)));
}
Console.WriteLine(sb);
}
}
how can I force the type passed as parameter has a field called "ID"?
You could create an interface:
public interface IWithID
{
// For your method the set(ter) isn't necessary
// public int ID { get; set; }
public int ID { get; }
}
public static void createDictionary<T>(IEnumerable<T> myRecords)
where T: IWithID
You'll need to use a property, not a field in this way.
Or clearly you could use a base type...
public abstract class WithID
{
// public int ID; // non readonly
public readonly int ID; // can even be a field
}
public static void createDictionary<T>(IEnumerable<T> myRecords)
where T: WithID
Another solution is to pass a delegate:
public static void createDictionary<T>(IEnumerable<T> myRecords,
Func<T, int> getID)
then you use the GetID to get the ID, like myRecords.ToDictionary(getID)
Inherit it from an interface that has ID defined.
public interface IIDInterface {
int ID { get; set; }
}
public static void createDictionary<T>(IEnumerable<T> myRecords)
where T: IIDInterface
The where syntax is meant to indicate that the class bases some other class. So you'd need a base class:
public abstract class IDBaseClass
{
public int ID { get; set; }
}
to then change it to something like this:
where T : IDBaseClass
Then, the types that you use there just need to base that class. Now, if you can't build an abstract class because your types are already basing something, you can use an interface:
public interface IIDInterface
{
int ID { get; set; }
}
and you could change the where syntax to be:
where T : IIDInterface
So then your types that use this generic class just need to implement that interface.
Inheritance http://msdn.microsoft.com/en-us/library/ms173149.aspx
you require a "base class" or an "interface" which has the property ID which all the classes implement
where T : BaseClassWithID
or
where T : IInterfaceWithID
I want to build a form entity, which should contain form form fields, so I want to have a class that looks something like this:
public abstract class form
{
public string FormName;
public IList<FormField> Fields;
}
I want my FormField class to have one method: getValue, but I want it to be generic, so getValue would not return an Object but the actual value of the object.
Unfortunately there is no way to create a single generic list containing objects, that each have a different return type for a given method, like the one you want.
The best you can do is an interface, or base class, and a method that returns Object.
This means you will have to cast, but then, you would have to do that anyway.
How would this code work if you could have different return types:
FormField f = _Fields[0];
?? x = f.GetValue();
This will work:
public abstract class Form<T>{
public string FormName;
public IList<IFormField> Fields;
}
public class FormField<T> : IFormField{
public T getValue() { return default(T); }
object IFormField.getValue() {
return this.getValue();
}
}
public interface IFormField {
object getValue();
}
public abstract class Form<T>{
public string FormName;
public IList<FormField<T>> Fields;
}
public class FormField<T>{
public T getValue { ... code here ... }
}
public abstract class Form {
public IList<FormField> Fields;
public string FormName;
}
public class FormField {
private Object field;
public T getValue<T>() {
return (T) field;
}
}
Please see the complete code below. My solution works like:
var myForm = new Form();
var int_value = myForm.Fields
.OfType<IntegerFormField>()
.First(c => c.Name == "c1").GetValue();
var decimal_value = myForm.Fields
.OfType<DecimalFormField>()
.First(c => c.Name == "c2").GetValue();
The field interfaces:
public interface IFormField
{
object GetValue();
string Name { get; }
}
public interface IFormField<T> : IFormField
{
T GetValue();
}
The abstract base class for all form fields:
abstract class FormFieldBase<T> : IFormField<T>
{
private readonly T _value;
public FormFieldBase(T value, string name)
{
_value = value;
Name = name;
}
#region IFormField<T> Members
public virtual T GetValue()
{
return _value;
}
#endregion
#region IFormField Members
object IFormField.GetValue()
{
return _value;
}
public string Name { get; private set; }
#endregion
}
Two sample form field implementation:
class IntegerFormField : FormFieldBase<int>
{
public IntegerFormField(int value, string name) : base(value, name) { }
}
class DecimalFormField : FormFieldBase<decimal>
{
public DecimalFormField(Decimal value, string name) : base(value, name) { }
}
The Form Class:
class Form
{
public IList<IFormField> Fields
{
get
{
return new List<IFormField>(){
new IntegerFormField(10, "c1"),
new DecimalFormField(200, "c2")
};
}
}
}
HTH