ObservableCollection of open generic type - c#

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.

Related

C# How to create a collection of generic class which derives from a specific implementation of another generic class which is a derived class

Struggling with wording that title to make any sense so I will just show my code and try and explain it
So I have this base class
public abstract class SpacecraftProperty
{
}
public abstract class SpacecraftProperty<T> : SpacecraftProperty
where T : SpacecraftProperty<T>
{
public abstract void Add(T property);
}
With this I can create a collection of SpacecraftProperty just fine thanks to the base SpacecraftProperty class that is not generic.
Then I have this class that derives from SpacecraftProperty that is also generic
public class ResourceStorage<ResourceType> : SpacecraftProperty<ResourceStorage<ResourceType>>
where ResourceType : ResourceInfo, new()
{
public ResourceType resource { get; private set; } = new ResourceType();
public float capacity { get; private set; }
public override void Add(ResourceStorage<ResourceType> property)
{
this.capacity += property.capacity;
}
}
Now the issus is that I need to create a collection of this ResourceStorage class, where each object in the collection can be of any type for ResourceType. But I can't use the same trick as above where I create a non-generic base class as then when I try and derive from SpacecraftProperty<>, it won't know what type of the generic SpacecraftProperty to derive from.
For completeness, here is the code for ResourceInfo, which is an abstract class which will be derived from
public abstract class ResourceInfo
{
public abstract string GetName();
public abstract string GetDescription();
}
So in summary I would for example want a collection that contains say a ResourceStorage<SomeTypeA>, ResourceStorage<SomeTypeB> etc. where SomeTypeA and SomeTypeB derive from ResourceInfo. And ResourceStorage derives from SpacecraftProperty, which has the generic method Add.
Any ideas?
But I can't use the same trick as above where I create a non-generic base class as then when I try and derive from SpacecraftProperty<>, it won't know what type of the generic SpacecraftProperty to derive from.
You can use the same trick. The type to derive from is SpacecraftProperty<ResourceStorage>, where ResourceStorage is the non-generic type you have created. This is because the implementation of Add in the generic ResourceStorage<T> doesn't actually use T.
// note that I've changed the naming conventions to match that of C#'s
public abstract class ResourceStorage: SpacecraftProperty<ResourceStorage> {
public abstract float Capacity { get; protected set; }
}
public class ResourceStorage<TResource> : ResourceStorage
where TResource: ResourceInfo, new()
{
public TResource Resource { get; private set; } = new TResource();
public override float Capacity { get; protected set; }
public override void Add(ResourceStorage property)
{
Capacity += property.Capacity;
}
}
ResourceStorage<TResource> is now a SpacecraftProperty<ResourceStorage>, however, and not a SpacecraftProperty<ResourceStorage<TResource>>.
To fix that, you can make the abstract classes contravariant interfaces instead. Since there is only one Add method:
public interface ISpacecraftProperty {}
public interface ISpacecraftProperty<in T> : ISpacecraftProperty
where T : ISpacecraftProperty<T>
{
void Add(T property);
}
public interface IResourceStorage: ISpacecraftProperty<IResourceStorage> {
public float Capacity { get; }
}
public class ResourceStorage<TResource> : IResourceStorage
where TResource: ResourceInfo, new()
{
public TResource Resource { get; private set; } = new TResource();
public float Capacity { get; private set; }
public void Add(IResourceStorage property)
{
Capacity += property.Capacity;
}
}
Now this compiles:
var list = new List<IResourceStorage>() {
new ResourceStorage<Foo>(),
new ResourceStorage<Bar>()
};
// This'd work too, but I'm sure you are aware already, since it is the nature of what you are trying to do
list[0].Add(list[1]);
ISpacecraftProperty<ResourceStorage<Foo>> x = new ResourceStorage<Foo>();
If ISpacecraftProperty has other methods that return a T, and so can't be contravariant, you can always just add ISpacecraftProperty<ResourceStorage<TResource>> as yet another interface of ResourceStorage<TResource>.
public class ResourceStorage<TResource> : IResourceStorage, ISpacecraftProperty<ResourceStorage<TResource>>
where TResource: ResourceInfo, new()
{
public TResource Resource { get; private set; } = new TResource();
public float Capacity { get; private set; }
public void Add(IResourceStorage property)
{
Capacity += property.Capacity;
}
// implement explicitly by delegation
void ISpacecraftProperty<ResourceStorage<TResource>>.Add(ResourceStorage<TResource> property) {
Add(property);
}
}

define a generic property in non-generic base class

I dont think what I am trying to do is possible; is there a way to actually make this work?
There is a Base class from which a variety of different classes are derived. Derived classes can be generic or not; instances of the derived classes are added to a collection of type Base in WindowViewModel. The Base class has a collection of Options that are accessed by the WindowViewModel.
The issue is: the IOption interface declares a return type of Func<object, bool> MyFunc but the return type of MyFunc needs to be Func<T, bool> for the generic class method RunIt() and for the assignment in MyClass to work. I could make the IOption generic, but then the Base class would need to be generic, and then the WindowViewModel.ViewModels would also need to be redefined somehow. I dont want to make the Base generic as introducing generics there just makes everything else a real mess.
Question: is there a different way to declare MyFunc in IOption without using generics to allow assignment of Func<T,bool> in MyClass ?
public interface IOption
{
public string Description {get; set;}
public Expression<Func<object,bool>> MyFunc { get; set; }
}
public class Option : IOption
{
public string Description {get; set;}
public Expression<Func<object,bool>> MyFunc { get; set; }
}
public abstract class Base
{
public abstract ObservableCollection<Option> Options { get; set; }
public abstract Option SelectedOption { get; set; }
public abstract void RunIt();
}
public class Generic<T> : Base
{
private DBContext _context;
public override ObservableCollection<Option> Options { get; set; }
public override Option SelectedOption { get; set; }
public Generic()
: base()
{
Options = new ObservableCollection<Option>();
}
public override void RunIt()
{
var result = _context.Set<T>().Where(SelectedOption?.MyFunc);
// process result
}
}
public class MyClass : Generic<MyType>
{
public MyClass
: base()
{
Func<MyType,bool> expression = t => t.MyDescription = "Hello World";
Options.Add(new Option("Hi", expression)); // fail to compile type mismatch
SelectedOption = Options.First();
}
}
public class Special : Base
{
// do something else
}
public class WindowViewModel
{
public WindowViewModel ()
{
MyViewModels = new ObservableCollection<Base>();
MyViewModels.Add(new Special());
MyViewModels.Add(new MyClass());
}
public ObservableCollection<Base> MyViewModels {get; set;}
public Base SelectedViewModel { get; set; }
public void DoRunIt()
{
SelectedViewModel.RunIt();
}
}
one of the things I did try that compiles but throws runtime exception when used, is
Func<MyType,bool> expression = t => t.MyDescription = "Hello World";
MyFunc = t => expression((MyType)t);
There is a way to do this. It uses the ability for all delegates (Func<MyType, bool> is a delegate) to be cast to Delegate.
You'd change IOption and Option to this:
public interface IOption
{
public string Description { get; set; }
Func<T, bool> GetMyFunc<T>();
}
public class Option : IOption
{
string description;
private Delegate expression;
public Option(string description, Delegate expression)
{
this.description = description;
this.expression = expression;
}
public string Description { get; set; }
public Func<T, bool> GetMyFunc<T>() => (Func<T, bool>)this.expression;
}
Then MyClass works as expected (except for the other syntax error in your code).
You then just need to change RunIt on Generic<T> to this:
public override void RunIt()
{
var result = _context.Set<T>().Where(SelectedOption?.GetMyFunc<T>());
// process result
}
Question: is there a different way to declare MyFunc in IOption without using generics to allow assignment of Func<T,bool> in MyClass ?
No, I don't believe that is possible. You can have generic methods in a non generic type, though.
However, there is an option that might work for you.
You state
I dont want to make the Base generic as introducing generics there just makes everything else a real mess.
How about having both?
public abstract class Base<T>
{
public abstract ObservableCollection<Option<T>> Options { get; set; }
public abstract Option<T> SelectedOption { get; set; }
public abstract void RunIt();
}
public abstract class Base : Base<object> { }

Using Generics in Expressions for overloaded collection parameters

I have created a class which has a method which is overloaded to accept a class or a collection of classes.
The problem is that the wrong overload is called for different types of collections. An example of this can be seen using this sample code I've created:
void Main()
{
GenericMethod(x => x.CollectionItems, ExpectedType.Collection);
GenericMethod(x => x.ListItems, ExpectedType.Collection);
GenericMethod(x => x.EnumerableItems, ExpectedType.Collection);
GenericMethod(x => x.CollectionTestSubClass, ExpectedType.Single);
}
public void GenericMethod<TPropType>(Expression<Func<CollectionTestClass, TPropType>> predicate, ExpectedType expectedType)
where TPropType : class
{
$"Single Method Called - Expected: {expectedType}".Dump();
}
public void GenericMethod<TPropType>(Expression<Func<CollectionTestClass, IEnumerable<TPropType>>> predicate, ExpectedType expectedType)
where TPropType : class
{
$"Collection Method Called - Expected: {expectedType}".Dump();
}
public class CollectionTestClass
{
public Guid Id { get; set; }
public ICollection<CollectionTestSubClass> CollectionItems { get; set; }
public IList<CollectionTestSubClass> ListItems { get; set; }
public IEnumerable<CollectionTestSubClass> EnumerableItems { get; set; }
public CollectionTestSubClass CollectionTestSubClass { get; set; }
}
public class CollectionTestSubClass
{
public Guid Id { get; set; }
}
public enum ExpectedType
{
Single,
Collection
}
The output will be:
So it is only the IEnumerable that will call the correct Collection method.
I would have thought that with ICollection and IList being implementations of IEnumerable that it may be able to figure out which method to call. Or is it a case that generics in C# are constraining to the point that even though other collections do implement IEnumerable it is only going to allow the explicit class specified to be used?
In which case would I have to write a overload for each collection type?

Covariance confusion. Can't assign tuples of implemented interfaces to list of tuples

Preface: I am aware that there are a lot of questions and answers about covariance and contravariance but I'm still feeling muddled and not sure what solution to implement.
I have two interfaces whose implementations are intended to be used together in pairs. One provides the information about a sales item and one provides language dependent information for a sales item.
I do not have control over these interfaces:
public interface IItem
{
decimal Price { get; set; }
}
public interface IItemTranslation
{
string DisplayName { get; set; }
}
I also have two implementations of both these interfaces for a tangible GoodsItem as well as an intangible ServiceItem. Again, I do not have control over these interfaces:
public class GoodsItem : IItem
{
public decimal Price { get; set; } //implementation
public float ShippingWeightKilograms { get; set; } //Property specific to a GoodsItem
}
public class GoodsTranslation : IItemTranslation
{
public string DisplayName { get; set; } //implementation
public Uri ImageUri { get; set; } //Property specific to a GoodsTranslation
}
public class ServiceItem : IItem
{
public decimal Price { get; set; } //implementation
public int ServiceProviderId { get; set; } // Property specific to a ServiceItem
}
public class ServiceTranslation : IItemTranslation
{
public string DisplayName { get; set; } //implementation
public string ProviderDescription { get; set; } // Property specific to a ServiceTranslation
}
As I said, these are classes that I do not have control over. I want to create a generic list of these pairings (List<Tuple<IItem, IItemTranslation>>) but I cannot:
public class StockDisplayList
{
public List<Tuple<IItem, IItemTranslation>> Items { get; set; }
public void AddSomeStockItems()
{
Items = new List<Tuple<IItem, IItemTranslation>>();
var canOfBeans = new Tuple<GoodsItem, GoodsTranslation>(new GoodsItem(), new GoodsTranslation());
var massage = new Tuple<ServiceItem, ServiceTranslation>(new ServiceItem(), new ServiceTranslation());
Items.Add(canOfBeans); //illegal: cannot convert from 'Tuple<GoodsItem, GoodsTranslation>' to 'Tuple<IItem, IItemTranslation>'
Items.Add(massage); //illegal: cannot convert from 'Tuple<ServiceItem, ServiceTranslation>' to 'Tuple<IItem, IItemTranslation>' }
}
Question: Without changing my IItem and ITranslation classes or their derived types, what's the cleanest way to be able to pass around a generic list of these pairings without casting them back and forth between the interface and their type?
Caveat. I was trying to simplify the question but I'm not actually using Tuples. In reality I'm using a class like this:
public class ItemAndTranslationPair<TItem, TItemTranslation> where TItem : class, IItem where TItemTranslation : class, IItemTranslation
{
TItem Item;
TTranslation Translation;
}
and my services are returning strongly typed lists, like List<ItemAndTranslationPair<GoodsItem, GoodsTranslation>> and therefore when I add items to the 'generic' list it looks like:
var differentBrandsOfBeans = SomeService.GetCansOfBeans();
//above variable is of type IEnumerable<ItemAndTranslationPair<GoodsItem, GoodsTranslation>>
var items = new List<ItemAndTranslationPair<IItem, IItemTranslation>>();
items.AddRange(differentBrandsOfBeans);
You need to create the tuples using the interface types:
var canOfBeans = new Tuple<IItem, IItemTranslation>(new GoodsItem(), new GoodsTranslation());
var massage = new Tuple<IItem, IItemTranslation>(new ServiceItem(), new ServiceTranslation());
As you're storing them in a list of Tuple<IItem, IItemTranslation> this should be a problem for you.
Use the out modifier on the type parameter of the generic type to obtain covariance in that parameter.
In the current version of C#, this is not supported for class types, only interface types (and delegate types), so you would need to write an interface (notice use of out):
public interface IReadableItemAndTranslationPair<out TItem, out TItemTranslation>
where TItem : class, IItem
where TItemTranslation : class, IItemTranslation
{
TItem Item { get; }
TItemTranslation Translation { get; }
}
Note that the properties cannot have a set accessor since that would be incompatible with the covariance.
With this type, you can have:
var differentBrandsOfBeans = SomeService.GetCansOfBeans();
//above variable is of type
//IEnumerable<IReadableItemAndTranslationPair<GoodsItem, GoodsTranslation>>
var items = new List<IReadableItemAndTranslationPair<IItem, IItemTranslation>>();
items.AddRange(differentBrandsOfBeans);
It works because IEnumerable<out T> is covariant, and your type IReadableItemAndTranslationPair<out TItem, out TItemTranslation> is covariant in both TItem and TItemTranslation.

How to Define that a Type T must have a field "ID"

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

Categories

Resources