define a generic property in non-generic base class - c#

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> { }

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);
}
}

One function for two different classes with similar properties

Hi after failing with inheritance (it got complicated) I stumble onto Generics. I am new to coding in general and C# is my first language.
I have two classes CIMTDXInput, RMTTDXInput which have the same properties but those properties have slightly different members. For those same 3 properties between the two, I want to just check if they are null or not.
So I wrote this:
public static TDX2KlarfResult CheckCIMTDXInput <T> (T input, TDX2KlarfResult result) where T: CIMTDXInput, RMTTDXInput
{
if (input.ToolContext == null)
{
Logger.Warn("Missing Tool Context Skipping the file");
result.errorType = "Warning";
result.errorMessage = "Missing Tool Context";
result.errorSubject = ErrorCategory.MISSING_TOOL_CONTEXT;
result.success = false;
return result;
}
if (input.SCContext == null)
{
Logger.Warn("Missing Context Skipping the file");
result.errorType = "Warning";
result.errorMessage = "Missing Context";
result.errorSubject = ErrorCategory.MISSING_CONTEXT;
result.success = false;
return result;
}
if (input.WaferContainer == null)
{
Logger.Warn("Missing Wafer Container Skipping the file");
result.errorType = "Warning";
result.errorMessage = "Missing Wafer Container";
result.errorSubject = ErrorCategory.MISSING_WAFER_CONTAINER;
result.success = false;
return result;
}
return result;
}
However the code won't compile. I thought you can assign as many classes as you want to the "T"?
Again both classes have ToolContext, SCContext, and WaferContainer. Instead of writing a function for each, I thought it would be elegant to write one for both. I also have additional inputs in the future to add so I'd like to not need to write this function each time
The why
So when you say this:
public void MyMethod<T>(T value) where T: ClassA, ClassB
You're saying that T should be derived from both ClassA and ClassB. Now it would work in this scenario:
public class ClassA
{
public int SomeProperty { get; set; }
}
public class ClassB : ClassA
{
}
public class ClassC : ClassB
{
}
MyMethod<ClassB>(classBValue); // ClassB is a ClassB and is derived from ClassA
MyMethod<ClassC>(classCValue); // ClassC is derived from ClassB, and is indirectly derived from ClassA
But this won't work:
public class ClassA
{
public int SomeProperty { get; set; }
}
public class ClassB
{
public int SomeProperty { get; set; }
}
Because it requires a ClassC that looks like this:
public class ClassC : ClassA, ClassB
{
}
And this could will cause a compile time error because C# doesn't support multiple inheritance. That is to say that, while you can have a class derived from a class that itself is derived from another class, you can't create a class that directly derives from two classes.
The solution
What you can do is declare an interface:
public interface ISomeInterface
{
int SomeProperty { get; set; }
}
And have both the classes implement it:
public class ClassA : ISomeInterface
{
public int SomeProperty { get; set; }
}
public class ClassB : ISomeInterface
{
public int SomeProperty { get; set; }
}
Then if we change our method signature to require that the class implements our interface:
public void MyMethod<T>(T value) where T: ISomeInterface
Then within the method we can access the SomeProperty property of T:
public void MyMethod<T>(T value) where T: ISomeInterface
{
value.SomeProperty *= 2;
}
Try it online
you need to use an interface
public interface IInput
{
public string ToolContext {get;set;}
public string SCContext {get;set;}
public string WaferContainer {get;set;}
}
public class CIMTDXInput:IInput
{
public string ToolContext {get;set;}
public string SCContext {get;set;}
public string WaferContainer {get;set;}
.... another properties
}
public class RMTTDXInput:IInput
{
public string ToolContext {get;set;}
public string SCContext {get;set;}
public string WaferContainer {get;set;}
.... another properties
}
and your method should be
public static TDX2KlarfResult CheckCIMTDXInput<T>(T input, TDX2KlarfResult result) where T : IInput
or you can get without a generic in this case , would be enough
public static TDX2KlarfResult CheckCIMTDXInput(IInput input, TDX2KlarfResult result)

Getting properties from generic type used in abstract superclass without using interfaces?

Is there any nice, elegant way to get properties from generic type used in abstract superclass without using interfaces?
Here's an example:
public abstract class CoolBase<T>
where T : class
{
private IEnumerable<T> somEnumerable;
public void GetPersonProperties()
{
var name = somEnumerable.First().Name; //this doesn't work
}
}
public class CoolA : CoolBase<Person>
{
}
public class Person
{
public string Name { get; set; }
public string Region { get; set; }
}
}
The goal of using generic classes is type-flexibility -
therefore it makes no sence to declare a method in a generic class which
uses Person-specific methods.
You should implement such detailed methods in the concrete implementations of
your abstract, generic class (here CoolA).
Maybe it is helpful for you to declare an abstract method getProperties()
int the generic, abstract class, wich can be implemented in CoolA via using
Person-specific code.
public abstract class CoolBase<T>
where T : class
{
private IEnumerable<T> somEnumerable;
public abstract void getProperties();
}
public class CoolA : CoolBase<Person>
{
public override void getProperties()
{
//should work, somEnumberable is made of Persons here
var name = somEnumerable.First().Name;
}
}
It makes no sense to put GetPersonProperties in CoolBase. CoolBase is generic, so should not have a class-specific functionality within it.
You could create a abstract method in CoolBase and implement it in your derived type:
public abstract class CoolBase<T> where T : class
{
protected IEnumerable<T> somEnumerable;
public abstract void GetProperties();
}
public class CoolA : CoolBase<Person>
{
public override void GetProperties()
{
var name = somEnumerable.First().Name;
}
}
public class Person
{
public string Name { get; set; }
public string Region { get; set; }
}
Alternatively, you could you reflection to get at the properties of T at runtime:
public abstract class CoolBase<T> where T : class
{
private IEnumerable<T> somEnumerable;
public void GetProperties()
{
foreach (var prop in typeof (T).GetProperties())
{
// do something with each property
}
}
}

ObservableCollection of open generic type

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.

How Can I Accept a Generic Class and Use Its Properties / Methods

I want to create a class that could hold any of a number of same type of classes. For example lets says I have a base class like follows:
public class BaseClass
{
public string MyBaseString
{
get;
set;
}
}
And then I have a few derived classes like this:
public class DerivedClass : BaseClass
{
public MyDerivedClassString
{
get;
set;
}
}
public class DerivedClass2 : BaseClass
{
public MyDerivedClass2String
{
get;
set;
}
}
Now I would like a class that accepts one of these implementations and does stuff with it. Here is the only thing I can think of, but there must be a better way:
public class ClassA
{
public object MyClass
{
get;
set;
}
public ClassA (object myClass)
{
MyClass = myClass;
if (object is BaseClass)
{
//do something
}
else if (object is DerivedClass)
{
//do something specific to derived class
}
else if (object is DerivedClass2)
{
//do something specific to derived class 2
}
}
}
CLARIFICATION: The specific goal I am trying to accomplish is to use ClassA as a container class for various implementations of the BaseClass. The business goal I am trying to accomplish is to create a Legend object which might use multiple color schemes (i.e. a Mono Color Ramp, Multi Color Ramp, etc). So I would like the Legend class to contain the ColorScheme that is being used, but still have access to that color scheme's unique properties for modification later on.
CLARIFICATION 2 Based on the wide array of responses I got, I thought I'd provide an exact replication of what I'm trying to do:
public class BaseColorScheme
{
List<Color> _colors = new List<Color>();
public List<Color> Colors
{
get
{
return _colors;
}
set
{
_colors = value;
}
}
}
public class SingleColorScheme : BaseColorScheme
{
public Color MidColor
{
get;
set;
}
public SingleColorScheme( Color midColor, int numberOfClassifications )
{
Colors = CreateMonoColorRamp( midColor, numberOfClassifications );
}
}
public class MultiColorScheme : BaseColorScheme
{
public Color StartColor
{
get;
set;
}
public Color EndColor
{
get;
set;
}
public Color MidColor
{
get;
set;
}
public MultiColorScheme( Color startColor, Color endColor, Color midColor )
{
StartColor = startColor;
EndColor = endColor;
MidColor = midColor;
Colors = //do something to define multi color scheme
}
}
Then I would have a Legend Class that would be something like
public class Legend
{
public object ColorScheme
{ get; set; }
public Guid LegendId
{ get; set; }
public Legend(object colorScheme)
{
ColorScheme = colorScheme;
}
}
Finally I might have a form that sits on top of the legend that displays the properties of the various color schemes based on which type of color scheme it is. Hopefully that helps clarify a bit.
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA(T myClass) { MyClass = myClass; }
}
Beyond that, define the common interface of the class hierarchy either as an interface or as methods (concrete, abstract, or virtual) within the base class. Then you can be assured all derived classes have such method / properties and can use them within your generic wrapper.
Instead of letting ClassA perform whatever needs to be done, you can use polymorphism and let the classes do it to themselves.
Simply declare a virtual method in the base class, have it do whatever you need it do so, and then override this method in the subclasses. In the method in ClassA, you just need to call that method on the object you receive as a parameter - without having to care about the specific type.
If you need to access different properties based on which derived class is passed something like this should help:
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA(T myClass) { MyClass = myClass; }
public void DoStuffToMyClass()
{
if(MyClass is BaseClass)
{ // do base class stuff }
else if(Myclass is DerivedClass)
{ // do DerivedClass stuff }
else if(MyClass is DerivedClass2)
{ // do DerivedClass2 stuff }
}
}
This gives you the type saftey to ensure you at least have the BaseClass object, and possibly a derived class.
The answer is polymorphism, let the object do it themselves.
public class BaseClass
{
public string MyString { get; set; }
public virtual string DoIt()
{
return "I'm Base Class";
}
}
public class DerivedClassA
{
public override string DoIt()
{
return "I'm Derived Class A";
}
}
public class DerivedClassB
{
public override string DoIt()
{
return "I'm Derived Class B";
}
}
....
public ClassA (BaseClass myClass)
{
MyClass = myClass;
MyClass.DoIt();
}
.....
ClassA x1 = ClassA(new BaseClass()) // calls BaseClass.DoIt()
ClassA x2 = ClassA(new DerivedClassA()) // calls DerivedClassA.DoIt()
ClassA x3 = ClassA(new DerivedClassB()) // calls DerivedClassB.DoIt()
whenever you catch yourself acting differently based on the run-time type of the object, you are dealing with code that breaks OO principles, i.e. a class that does not respect the base class contract.
Can you use virtual methods?
public abstract class BaseClass
{
public abstract void DoStuff();
}
public class DerivedClass1 : BaseClass
{
public override void DoStuff()
{
...
}
}
public class DerivedClass2 : BaseClass
{
public override void DoStuff()
{
...
}
}
Without generics:
public class ClassA
{
public BaseClass MyClass
{
get;
set;
}
public ClassA (BaseClass myClass)
{
MyClass = myClass;
myClass.DoStuff();
}
}
or with generics:
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA (T myClass)
{
MyClass = myClass;
myClass.DoStuff();
}
}
Keep it simple: polymorphism
Hopefully your objects have a common interface, something like:
class Base {
public virtual void DoSomething() { /* Default implementation */ }
}
class Derived1 : Base {
public override void DoSomething() { /* Implementation specific to this type */ }
}
class Derived2 : Base {
public override void DoSomething() { /* Another implementation specific to this type */ }
}
Or maybe they implement a common interface. So hopefully your consuming class can hold the most general representation of your inputs as possible and invoke code as such:
class Dependent {
public Dependent(Base instance) {
instance.DoSomething();
}
}
So your Dependent class doesn't really are whether it has a derived type or a base type.
Not quite as simple: visitor pattern
Sometimes polymorphism doesn't really work, which is particularly the case if you need to access the specific members of your derived classes, and those members aren't in the base class. Visitor pattern works well in this case, especially if you have a fixed, well-defined graph of objects.
public interface IVisitor<T> {
T Visit(Base x);
T Visit(Derived1 x);
T Visit(Derived2 x);
}
class Base {
public virtual T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string BaseString { get; set; }
}
class Derived1 : Base {
public override T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string Derived1String { get; set; }
}
class Derived2 : Base {
public override T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string Derived2String { get; set; }
}
So Derived1 and Derived2 have a different set of properties, and if you need to get to those properties without a runtime type-checking, implement a visitor:
class DefaultStringVisitor : IBaseVisitor<string> {
public string Visit(Base x) { return x.BaseString; }
public string Visit(Derived1 x) { return x.Derived1String; }
public string Visit(Derived2 x) { return x.Derived2String; }
}
class Dependent {
public Dependent(Base x) {
string whatever = x.Accept<string>(new DefaultStringVisitor());
}
}
So the visitor pattern gives you access to your derived object's members without a type-check. Its a somewhat inflexible pattern (i.e. need to know which objects to visit up front), but it might work for your needs.

Categories

Resources