custom generic collection- what is the best way to refactor it? - c#

I have a similar problem and tried to depict it with code as it is easier to explain.
Basically I have a generic collection, so irrespective of which type of collection its instantiated as, it will have some common properties and events. And I am interested in these common properties.
Say, I have the instantiated obect of the generic collection - what is the best way to get these properties and subscribe to the events? I understand I can do it by implementing an interface and casting it to the interface definition but I don't like doing that as I am just doing it to please a single requirement. Is there a better way to refactor this?
public interface IDoNotLikeThisInterfaceDefinitionJustToPleaseGetDetailMethod
{
string Detail { get; }
event Action<bool> MyEvent;
}
public class MyList<T> : List<T>
//, IDoNotLikeThisInterfaceDefinitionJustToPleaseGetDetailMethod
{
public string Detail
{
get;
}
}
class Program
{
static void Main(string[] args)
{
MyList<int> mi = new MyList<int>();
MyList<string> ms = new MyList<string>();
MyList<char> mc = new MyList<char>();
GetDetail(mi);
GetDetail(ms);
GetDetail(mc);
}
//please note that obect need not be mylist<t>
static string DoSomeWork(Object object)
{
//Problem: I know myListObect is generic mylist
//but i dont know which type of collection it is
//and in fact i do not care
//all i want is get the detail information
//what is the best way to solve it
//i know one way to solve is implement an interface and case it to get details
var foo = myListObject as IDoNotLikeThisInterfaceDefinitionJustToPleaseGetDetailMethod;
if (foo != null)
{
//is there another way?
//here i also need to subsribe to the event as well?
return foo.Detail;
}
return null;
}
}

You can make your method generic:
static string GetDetail<T>(MyList<T> myList)
{
return myList.Detail;
}
This will allow you to call it with the same code you already have written, and completely eliminate the interface.
Edit in response to comments:
Given that you don't know the type, and you're just checking against an object, it does seem like an interface is the best approach here. Providing a common interface allows you to expose all of the members you need regardless of what's contained within the collection, which provides the correct behavior.

Make your GetDetail method generic:
static string GetDetail<T>(MyList<T> list)
{
return list.Detail;
}

EDIT: I've assumed that there are potentially multiple collection classes involved. If there's actually only one class - MyList<T> - then using a generic method is absolutely the right way to go.
i understand i can do it by implementating an interface and casting it to the interface defenition but i dont like it as i am just doing it to please one single requirement.
You're doing it to express what the collections have in common. Unless the common members are implementing an interface, they just happen to have the same name - the interface shows that they have the same intended meaning too.
Using an interface is the right way to go here - but it's not clear why your GetDetail method doesn't just take the interface as a parameter... assuming you need the method at all.

Related

Generic handling in c#

So, I have a little bit of an issue that I can't exactly wrap my head around.
So, I have a base class called Property, and I have a lot of classes that derive from that one, like IntProperty, ColorProperty and so on. Now, I also have a few of them that are of the enum type and currently they are all separate classes. I'd like to make it a generic class but here's the issue with this:
In a different part of the code I need to handle all of them. Keep in mind I can't use virtual functions for this (I'm doing something with the UnityEditor).
Currently, I have a function that takes a Property as a parameter and then I do this for all types that derive from Property:
if(property is IntProperty)
{
IntProperty intProperty = property as IntProperty;
intProperty.theValue = specific_int_function();
}
That specific_int_function is the same for all enum values privided I have the T from a generic.
Ideally I'd like to do something like this (pseud-ish code):
(using T)
{
if(property is EnumProperty<T>)
{
EnumProperty<T> enumProperty = property as EnumProperty<T>;
enumProperty.value = (T)my_enum_value_function(typeof(T));
}
}
Any idea about how I could make all this code nicer?
Hopefully I provided all the relevant information.
Edit:
It's not so much that I can't use virtual functions in those classes but I can't call any of the specific functions in that particular file. I have 2 compilation groups and only one can access those functions (EditorGUI functions for people who know what I'm talking about)
Regards,
Lorin
Keep in mind I can't use virtual functions for this (I'm doing something with the UnityEditor).
That's really what you should be doing. If you can't, then fine, but I'm leaving this note here for the benefit of other people will be reading this question and answer too.
In my experience, the least difficult way of achieving this is with a helper class, because it lets you avoid some of the reflection complexity that you would have to deal with if you used a generic helper method.
abstract class EnumPropertyHelper {
public abstract void DoSomething(Property property);
}
class EnumPropertyHelper<T> : EnumPropertyHelper {
public override void DoSomething(Property property) {
EnumProperty<T> enumProperty = property as EnumProperty<T>;
enumProperty.value = (T)my_enum_value_function(typeof(T));
}
}
Then,
if (property.GetType().IsGenericType
&& property.GetType().GetGenericTypeDefinition() == typeof(EnumProperty<>)) {
var helperType = typeof(EnumPropertyHelper<>).MakeGenericType(property.GetType().GetGenericTypeArguments());
var helper = (EnumPropertyHelper)Activator.CreateInstance(helper);
helper.DoSomething(property);
}
But you do need to jump through hoops similar to this one whatever you end up doing, because C# and .NET don't allow you to have generic code in non-generic methods.
You could use add a function pointer to the class, and each constructor could implement it's own function?
Add a property Func<void> functionPTR = null
In each class you'd have a function such as
void specific_int_function() {
//Do Something
}
In the class constructor
functionPTR = specific_int_function;
And then in the generic class
void GenericHandler() {
functionPTR();
}
I'm not sure about the syntax, but this should give you the performance you're going for.
Read up on function pointers to see how to define the return value and function parameters.

Can we call method in implementation class not defined in its interface using interface variable?

Is it possible to call a method in implementation class of an interface which is not defined in interface using interface variable like below:
interface ILookup {
public void someInterfaceMethod1();
public void someInterfaceMethod2();
}
...and implementation class:
public class extendedLookUpImplementor: ILookup
{
//constructor
LookUpImplementor(){
}
public void someInterfaceMethod1(){
// Implementation Code here.
}
public void someInterfaceMethod2(){
// Implementation Code here.
}
public void ExtendedMethod(){
// Implementation Code here.
}
}
In client code:
ILookup lookupVar = new LookUpImplementor();
lookupVar -> someInterfaceMethod1(); // i know it will work.
lookupVar -> someInterfaceMethod2(); // i know it will work.
My question is, can i call ExtendedMethod using lookupVar like below:
lookupVar -> ExtendedMethod(); // Note again that ExtendedMethod() is not defined in Ilookup interface/contract.
Only by casting lookupVar as extendedLookUpImplementor, or by reflection I think.
First of all as Ian1971 said, yes you can by casting it to specific type, say
ILookup lookupVar = new LookUpImplementor();
((extendedLookUpImplementor)lookupVar).ExtendedMethod(); //this should work
or alternatively using dynamic/reflection.
Having said that, I really really don't think this is a good way to do this because it would violate one of the objective of contract/interface.
For instance, if we have ILookup variable "lookupVar"
dynamic lookup = lookupVar;
lookup.ExtendedMethod(); //this would work
At any point in time, the code utilizing the object lookupVar does not guarantee that there would be a method ExtendedMethod and can throw on Exception on run time.
My real question to you would be, why you want to add a method that cannot be added in contract, what is your objective here. If the method is extending the class, try going through C# extension method as they might fit in your scenario.

How to access static methods of generic types

public class BusinessObjects<O>
where O : BusinessObject
{
void SomeMethod()
{
var s = O.MyStaticMethod(); // <- How to do this?
}
}
public class BusinessObject
{
public static string MyStaticMethod()
{
return "blah";
}
}
Is there a correct object oriented approach to accomplishing this or will I need to resort to reflection?
EDIT: I went too far in trying to oversimplify this for the question and left out an important point. MyStaticMethod uses reflection and needs the derived type to return the correct results. However, I just realized another flaw in my design which is that I can't have a static virtual method and I think that's what I would need.
Looks like I need to find another approach to this problem altogether.
You can't access a static method through a generic type parameter even if it's constrained to a type. Just use the constrained class directly
var s = BusinessObject.MyStaticMethod();
Note: If you're looking to call the static method based on the instantiated type of O that's not possible without reflection. Generics in .Net statically bind to methods at compile time (unlike say C++ which binds at instantiation time). Since there is no way to bind statically to a static method on the instantiated type, this is just not possible. Virtual methods are a bit different because you can statically bind to a virtual method and then let dynamic dispatch call the correct method on the instantiated type.
The reason you can't reference the static member like this:
O.MyStaticMethod();
Is because you don't know what type O is. Yes, it inherits from BusinessObject, but static members are not inherited between types, so you can only reference MyStaticMethod from BusinessObject.
If you are forcing O to inherit from BusinessObject, why not just call it like this:
void SomeMethod()
{
var s = BusinessObject.MyStaticMethod(); // <- How to do this?
}

C# What is the best way to determine the type of an inherited interface class?

In my application I work with criterias. I have one base Criteria interface and and other interfaces who inherits from this base interface:
ICriteria
|
|
----------------------
| |
ITextCriteria IChoices
What I'd like to know is, what is the best way to know what Type the class is?
In my code I have a dropdown box and based on that I have to determine the type:
// Get selected criteria
var selectedCriteria = cmbType.SelectedItem as ICriteria;
if (selectedCriteria is IChoices)
{
//selectedCriteria = cmbType.SelectedItem as IChoices; Doesn't work
IChoices criteria = selectedCriteria as IChoices;//cmbType.SelectedItem as IChoices;
SaveMultipleChoiceValues(criteria);
//_category.AddCriteria(criteria);
}
else
{
//ICriteria criteria = selectedCriteria; //cmbType.SelectedItem as ICriteria;
if (selectedCriteria.GetCriteriaType() == CriteriaTypes.None)
{
return;
}
//_category.AddCriteria(criteria);
}
_category.AddCriteria(selectedCriteria);
selectedCriteria.LabelText = txtLabeltext.Text;
this.Close();
My question is, is this the best way? Or is there a better way to achieve this?
The chance is big that there are coming more interfaces based on ICriteria.
EDIT:
I have 2 types of controls which I want to add dynamically to my application. One control is a textbox and the other is a radio button.
For a radio button the user can define the options. When the options are defined, the user must choose one of the options and the chosen option must be saved in the database (this is later used to perform search operations). So, when the Save button is clicked, I have to determine the chosen type (radio or text) and save the answer possibilities (if it is a radio).
For a textbox, this doesn't have any answer possibilities. For that reason it has a different interface.
I hope I make it a little bit clearer now. Here is another question which is related: C# How to implement interface where concrete classes differs?
EDIT II:
This is how my method SaveMultipleChoiceValues looks like:
private void SaveMultipleChoiceValues(IChoices criteria)
{
foreach (DataGridViewRow row in dgvCriteriaControls.Rows)
{
if (row == dgvCriteriaControls.Rows[dgvCriteriaControls.Rows.Count - 1])
continue;
//multipleChoice.AddChoice(row.Cells["Name"].Value.ToString());
string choice = row.Cells["Name"].Value.ToString();
criteria.AddChoice(choice);
}
}
This looks like a prime example for polymorphism.
Instead of trying to do a type switch on your ICriteria implementation, why don't you add a method to ICriteria (or possibly a virtual method to some common base class of all ICriteria implementations), and just call that?
Obviously the implementation of this method would need access to objects that do not belong in your ICriteria instances, but that is a problem you can solve using other design patterns according to the specifics of your scenario.
Update:
Here's a complete solution, incorporating the code you posted:
Create a new interface ICriteriaView which models the view (in your case a Form) where ICriteria are displayed. The form needs to do some processing depending on the exact interface that criteria implement, so add a method with one overload for each interface that exists in your code. Do not add an overload for ICriteria itself. [1]
interface ICriteriaView {
void ProcessCriteria(IChoices criteria);
void ProcessCriteria(ITextCriteria criteria);
}
Your form will implement this interface, providing methods where suitable processing for each subtype of ICriteria will occur:
class MyForm : ICriteriaView {
public void ProcessCriteria(IChoices criteria) {
this.SaveMultipleChoiceValues(criteria);
}
public void ProcessCriteria(ITextCriteria criteria) {
// do nothing
}
private void SaveMultipleChoiceValues(IChoices criteria)
{
foreach (DataGridViewRow row in dgvCriteriaControls.Rows)
{
if (row == dgvCriteriaControls.Rows[dgvCriteriaControls.Rows.Count - 1])
continue;
//multipleChoice.AddChoice(row.Cells["Name"].Value.ToString());
string choice = row.Cells["Name"].Value.ToString();
criteria.AddChoice(choice);
}
}
}
Each implementation of ICriteria will need to implement a method which calls the appropriate ICriteriaView overload for its type. This is where the "redirection magic" happens: we will use polymorphism to get the compiler to "discover" the actual type of ICriteria our object is, and then use method overloading on ICriteriaView.ProcessCriteria to access the appropriate code.
interface ICriteria {
void PerformProcessingOn(ICriteriaView view);
}
interface IChoices : ICriteria {
}
interface ITextCriteria : ICriteria {
}
And this is where the dispatch to the appropriate overload happens:
class MultipleChoice : IChoices {
public PerformProcessingOn(ICriteriaView view) {
view.ProcessCriteria(this);
}
}
class SimpleInput : ITextCriteria {
public PerformProcessingOn(ICriteriaView view) {
view.ProcessCriteria(this);
}
}
Then, your code would do:
// Get selected criteria
var selectedCriteria = cmbType.SelectedItem as ICriteria;
// Here's where polymorphism kicks in
selectedCriteria.PerformProcessingOn(this);
// Finally, code that runs the same for all objects
_category.AddCriteria(selectedCriteria);
selectedCriteria.LabelText = txtLabeltext.Text;
this.Close();
Maintenance:
Whenever you add a new ICriteria sub-interface implementation, the definition of ICriteria will force you to implement the PerformProcessingOn method on it. Inside that method, all you can do really is call view.ProcessCriteria(this). In turn, this will force you to implement an appropriate ProcessCriteria overload in ICriteriaView and MyForm.
As a result, we have achieved two important objectives:
The compiler will not allow you to add a new ICriteria implementation without specifying exactly how that implementation should interact with ICriteriaView.
It is easy to discover from source code exactly what MyView does with e.g. IChoices when reading the code for MultipleChoice. The structure of the code leads you to MyForm.SaveMultipleChoiceValues "automatically".
Notes:
[1] The choice of adding an overload for ICriteria itself or not is really a tradeoff:
If you do add one, then code like this:
class MultipleChoice : IChoices {
public PerformProcessingOn(ICriteriaView view) {
view.ProcessCriteria(this);
}
}
will compile successfully always, because even if there is no ICriteriaView.ProcessCriteria(IChoices) overload there will still be the ICriteriaView.ProcessCriteria(ICriteria) overload that the compiler can use.
This means that, when adding a new ICriteria sub-interface implementation, the compiler will no longer force you to go check if the implementation of ICriteriaView.ProcessCriteria(ICriteria) really does the right thing for your new implementation.
If you do not add one, then the moment you write view.ProcessCriteria(this); the compiler will force you to go check (and update) ICriteriaView and MyForm accordingly.
In this scenario, and with the information you have provided, I believe that the appropriate choice would be the last one.
[2] As you can see above, the implementation of ICriteria.PerformProcessingOn inside MultipleChoice and SimpleInput looks exactly the same. If these two classes have a common base (which is quite possible in practice), you might be tempted to move the "duplicated" code into that base. Do not do that; it will cause the solution to break.
The tricky part is that inside MultipleChoice, when you do view.ProcessCriteria(this); the compiler can infer that the static type of this is IChoices -- this is where the redirection happens! If you move the call to ProcessCriteria inside a hypothetical base class CriteriaBase : ICriteria, then the type of this will become ICriteria and the dispatch of the call to the appropriate ICriteriaView.ProcessCriteria overload will no longer work.
You could do this:
var selectedCriteria = cmbType.SelectedItem as ICriteria;
if (typeof(IChoices).IsAssignableFrom(selectedCriteria.GetType()))
{
IChoices criteria = selectedCriteria as IChoices;
SaveMultipleChoiceValues(criteria);
}
else if(typeof(ITextCriteria).IsAssignableFrom(selectedCriteria.GetType()))
{
if (selectedCriteria.GetCriteriaType() == CriteriaTypes.None)
{
return;
}
}
But polymorphism is probably your best bet.
That is not the best way. If you are performing different actions based on the type of an object, you should probably be using polymorphism instead for a myriad number of reasons.
How you use polymorphism depends on what you actually need to have done based on the different types of ICriteria that are being used. If you just need to get a string containing all of their members, you could easily add a method to ICriteria and hand the responsibility to the class itself instead of the code that depends on it. This reduces duplication, puts code in a logical place, and makes sure you don't forget to add code for a new type of ICriteria.
If you give us more information on how you want different types to be treated/behave, we can probably give you more specific advice. :D
Here is a long term solution to an ever expanding list of critera without having to add more if/then/else.
While this code is complex to someone not used to designing in this manner, it allows you to keep your method dealing with criteria the same, and just register new delegates to handle additional criteria.
The idea is to create a map of Type objects that hold delegates in which to execute. You can then register new delegates to execute based on new Types as you generate them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Stackoverflow_4527626
{
delegate void CriteraDelegate(params object[] args);
class CriteraManager
{
private Dictionary<Type, CriteraDelegate> criterian = new Dictionary<Type, CriteraDelegate>();
public void RegisterCritera(Type type, CriteraDelegate del)
{
criterian[type] = del;
}
public void Execute(Object criteria, params object[] args)
{
Type type = criteria.GetType();
/// Check to see if the specific type
/// is in the list.
if (criterian.ContainsKey(type))
{
criterian[type](args);
}
/// If it isn't perform a more exhaustive search for
/// any sub types.
else
{
foreach (Type keyType in criterian.Keys)
{
if (keyType.IsAssignableFrom(type))
{
criterian[keyType](args);
return;
}
}
throw new ArgumentException("A delegate for Type " + type + " does not exist.");
}
}
}
interface InterfaceA { }
interface InterfaceB1 : InterfaceA { }
interface InterfaceB2 : InterfaceA { }
interface InterfaceC { }
class ClassB1 : InterfaceB1 { }
class ClassB2 : InterfaceB2 { }
class ClassC : InterfaceC { }
class Program
{
static void ExecuteCritera1(params object[] args)
{
Console.WriteLine("ExecuteCritera1:");
foreach (object arg in args)
Console.WriteLine(arg);
}
static void ExecuteCritera2(params object[] args)
{
Console.WriteLine("ExecuteCritera2:");
foreach (object arg in args)
Console.WriteLine(arg);
}
static void Main(string[] args)
{
CriteraDelegate exampleDelegate1 = new CriteraDelegate(ExecuteCritera1);
CriteraDelegate exampleDelegate2 = new CriteraDelegate(ExecuteCritera2);
CriteraManager manager = new CriteraManager();
manager.RegisterCritera(typeof(InterfaceB1), exampleDelegate2);
manager.RegisterCritera(typeof(InterfaceB2), exampleDelegate2);
manager.RegisterCritera(typeof(InterfaceC), exampleDelegate1);
ClassB1 b1 = new ClassB1();
ClassB2 b2 = new ClassB2();
ClassC c = new ClassC();
manager.Execute(b1, "Should execute delegate 2");
manager.Execute(b2, "Should execute delegate 2");
manager.Execute(c, "Should execute delegate 1");
}
}
}

C#: Subclass List<Something>?

I have a class EqualCondition which implements my own interface ICondition, which has only one method: SatisfiedBy(Something).
public class EqualCondition : ICondition {
private Something m_Something;
public HelloCondition(Something something) {
m_Something = something;
}
// Magic!!!
public bool SatisfiedBy(Something something) {
return something == m_Something;
}
}
So ICondition is very simple to implement. Now I'm trying to create a CombinationCondition which also implements it. The idea is that CombinationCondition which will contain a list of IConditions which will determine whether SatisfiedBy will be successful or not.
My first thought was to make CombinationCondition implement IList<Something> but I quickly realized that I was only duplicating List<Something>. So why not just subclass it?
That idea sounded fine until I started thinking again about how to implement SatisfiedBy if I just subclassed List<Something>. I need to do:
return innerList.All(x => x.SatisfiedBy(something))
But how do I access the inner list?
Personally, for the use case you're showing, I would just make this implement IEnumerable<Condition>. You could then just implement the GetEnumerator by calling the (internal, encapsulated) List<Condition>'s method.
Potentially, ICollection<Condition> may make more sense (so you can add conditions at runtime), but only if you need that capability. Implementing IList<T> seems like overkill in this situation, for the use cases I'd see with this.
From what you have posted, I would just have CombinationCondition contain (encapsulate) a List<Something>. No need for the outside world to know it is a list unless absolutely necessary.
Edit 1:
public class CombinationCondition : ICondition {
private List<ICondition> list;
public CombinationCondition(List<ICondition> list) {
this.list = list;
}
// if you need it
public void AddCondition( ICondition condition ){
list.Add( condition );
}
// Still Magic!!!
public bool SatisfiedBy(Something something) {
return list.Any( x => x.SatisfiedBy( something ) );
}
}
Edit 2:
You might also consider renaming CombinationCondition to CompoundCondition...makes more sense, at least to me :)
I'm not sure I 100% understand what you are trying to do, but would this solve your need?
public interface ICondition<T>
{
bool SatisfiedBy(T something);
}
That way, you can just implement it for any generic type you need
One possibility would be a property of type IList<ICondition> called maybe "Conditions".
You don't need to access the inner list - you could access your class "itself".
However, prefer sublassing from ICollection<T>.

Categories

Resources