C#: Subclass List<Something>? - c#

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>.

Related

Is it possible to return generic class based on enum input?

I am writing a small email templating engine using Razor syntax to fill in the tokens. I have a few email types:
public enum EmailType { Welcome, Reminder }
These types have corresponding templates and models, so for example Welcome email has a template:
<p>Welcome, #Model.Name</p>
and a corresponding model:
public class WelcomeModel { public string Name { get; set; } }
Now I wanted to create a method that will force a correct model for given enum, I would imagine something like this:
public ITemplate<T> GenerateTemplate(EmailType emailType)
{
switch (emailType)
{
case EmailType.Welcome:
return new EmailTemplate<WelcomeModel>();
case EmailType.Reminder:
return new EmailTemplate<ReminderModel>();
// ...
}
where EmailTemplate<T> : ITemplate<T>, so then I could chain the method:
engine
.GenerateTemplate(EmailType.Welcome)
.WithModel(new WelcomeModel()) // this knows it wants WelcomeModel
// and should complain with compiler error otherwise
The code that I've shown here does not compile because T is unknown. However this T cannot be infered:
public ITemplate<T> GenerateTemplate<T>(EmailType emailType)
which leaves me with:
engine
.GenerateTemplate<WelcomeModel>(EmailType.Welcome)
.WithModel(new WelcomeModel());
That works, but I feel like I'm passing redundant information - both enum and model, while you can deduce one from another. I am not sure if I'm missing something from C# or maybe my whole concept is not good. I think I'm in a dead end since I think I cannot return two separate, strongly typed classes from one method.
Is it possible to return generic model based on enum input?
Is it possible to return generic class based on enum input?
No. Not in a way that would be useful to the caller.
Your method returns ITemplate<T>. But T has to be defined as something at compile time. You cannot defer the definition to runtime, except by using late-binding (i.e. dynamic) or non-type-safe mechanisms (which negates the whole point of using generics).
Possibly if you could reframe your question and explain why it is you think it's reasonable to call a method that returns an open generic type ITemplate<T> without the call site understanding what the type parameter T actually is, a helpful solution could be found.
But as stated in your question thus far, the only real answer is, no that can't work and wouldn't make any sense if it could.
Couldn't you just do something like this?
switch (emailType)
{
case EmailType.Welcome:
return engine.GenerateTemplate().WithModel(new WelcomeModel());
case EmailType.Reminder:
return engine.GenerateTemplate().WithModel(new ReminderModel());
}
public ITemplate<T> GenerateTemplate<T>()
{
return new EmailTemplate<T>();
// ...
}
public interface ITemplate<T>
{
void WithModel(T model);
}
public class EmailTemplate<T> : ITemplate<T>
{
void WithModel(T model)
{
// ...
}
}
No, because C# does not support true generic polymorphism and diamond operator yet to allow to write:
public Template<> GenerateTemplate(EmailType emailType)
{
switch (emailType)
{
case EmailType.Welcome:
return new EmailTemplate<WelcomeModel>();
case EmailType.Reminder:
return new EmailTemplate<ReminderModel>();
}
}
The only thing you can do is to simulate that by using a non generic top interface like:
ITemplate<T> : ITemplate
Hence the creator method will returns ITemplate:
public ITemplate GenerateTemplate(EmailType emailType)
{
switch (emailType)
{
case EmailType.Welcome:
return new EmailTemplate<WelcomeModel>();
case EmailType.Reminder:
return new EmailTemplate<ReminderModel>();
}
}
But in your case if you prefer having true generic you need to create several methods:
EmailTemplate<WelcomeModel> GenerateWelcomeTemplate()
=> new EmailTemplate<WelcomeModel>();
EmailTemplate<ReminderModel> GenerateReminderTemplate
=> new EmailTemplate<ReminderModel>();
Then you will check the enum before calling them.
Doing this is more consistant with your code:
if ( EmailType.Welcome )
engine.GenerateWelcomeTemplate().WithModel(new WelcomeModel());
Here the code is more clean.
But I don't understand why you provide WithModel(new WelcomeModel()) after creating EmailTemplate<WelcomeModel>... it's redundant, isn't it?

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.

Different binding in specific object subtree using Ninject

I am using Ninject to perform dependency injection in my project and I've encountered one problem. I need to specify an exception in binding in specific subtrees of my "object tree" (in meaning of inclusion not inheritance). Let's say we have few interfaces and classes (I've excluded constructors and other irrelevant stuff):
interface Wheel { ... }
class RoundWheel : Wheel { ... }
class SquareWheel : Wheel { ... }
class Mechanism { Wheel Wheel; ... }
class Bike { Wheel Wheel; ... }
class Items { Mechanism Mechanism; Bike Bike; ... }
I want to bind Wheel to SquareWheel when it's somehow included in Mechanism (Mechanism can be somewhere higher, eg. Item.Mechanism.ContainerForWheel.(any types further on).Wheel) and to RoundWheel otherwise. Now, let's look at my current solution:
IKernel kernel = new StandardKernel();
kernel.Bind<Wheel>().To<RoundWheel>();
kernel.Bind<Wheel>().To<SquareWheel>().When(x => x.ActiveBindings.Any(p => p.Service.Name == typeof(Mechanism).Name));
Items items = kernel.Get<Items>();
It works like a charm, but looks very inelegant and suboptimal. It's hard to understand clear purpose of this filtering. Do you know any other way to achieve this? Thanks in advance.
Edit 1
I forgot to mention that I don't want to put any annotations and other stuff into my classes. I want to keep everything in kernel setup/modules.
I don't think there's really an easier way to do things. You could also explictly traverse the IContext.ParentRequest and check if there's ever a specific Mechanism. That would be a bit more explicit then using the ActiveBindings property. But will neither be faster nor result in less code.
But what you could do is applying clean code and creating your own When-Extension, so you'll end up with:
kernel.Bind<Wheel>().To<SquareWheel>()
.When(IsDescendantOf<Mechanism1>);
private static bool IsDescendantOf<T>(IRequest request)
{
return request.ActiveBindings.Any(p => p.Service.Name == typeof(T).Name);
}
or, using an extension method:
kernel.Bind<IWheel>().To<Wheel2>()
.WhenIsDescendantOf(typeof(Mechanism1));
public static class NinjectWhenExtensions
{
public static IBindingInNamedWithOrOnSyntax<T> WhenIsDescendantOf<T>(this IBindingWhenSyntax<T> syntax, Type ancestor)
{
return syntax.When(request => request.ActiveBindings.Any(p => p.Service.Name == ancestor.Name));
}
}
btw., you should also be able to replace the check p.Service.Name == typeof(Mechanism).Name by p.Service == typeof(Mechanism). When the name is a match, the type shoould be, too. If you're working with interface you would have to adapt the logic, though.

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

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.

Hashset not adding a duplicate, but returning true for Add()

(edit) more info. First notice "new virtual". This class inherits a base class which is supposed to be a generic parent-aware class that can be created with any ICollection type. Here's the descriptor, basically:
public abstract class ParentAwareCollection<TObject, TParent, TInnerList> :
ICollection<TObject>, ICollection, IParentProvider<TParent>
where TObject : IParentProvider<TParent>
where TInnerList : ICollection<TObject>, new()
{
protected TInnerList InnerList = new TInnerList();
...
}
This class:
public class ParentAwareHashset<TObject, TParent> :
ParentAwareCollection<TObject, TParent, HashSet<TObject>>, ISet<TObject>,
ICollection where TObject : IParentProvider<TParent>
{
public ParentAwareHashset(TParent parent)
: base(parent)
IParentProvider just requires that a "ParentCollection" object be present.
In debugging, the overridden (void) Add method in ParentAwareCollection is never called. So I don't think that the "new" is the problem.
Also, here's something that I also don't understand. Here's the descriptor for an actual HashSet:
public class HashSet<T> : ISerializable, IDeserializationCallback,
ISet<T>, ICollection<T>, IEnumerable<T>, IEnumerable
{
...
public bool Add(T item);
}
Notice that in implements ICollection just like mine. That is what led me to believe that this was OK to do. However unlike mine, the framework HashSet does not use a new descriptor for its Add() method, but that's required because ICollection<T> implements void Add(T item). Perhaps they just omitted it?
Original question:
I have a collection class that uses a HashSet<T> to store its objects. The objects of type T override GetHashCode(), in which they make sure that certain required information is present that is used to produce the hash code. I am not sure if this is important.
What happens is that when I do an Add(T) to the HashSet, it does not add the object, but returns true. If I debug and then in the immediate window try to add it again, it returns false, like it's supposed to. The method looks like this:
public new virtual bool Add(TObject item)
{
// Must add parent first, since it may be used in the hash code
// InnerList is a HashSet<T>
if (InnerList.Any(existing=>item.GetHashCode()==existing.GetHashCode())) {
return(false);
} else {
if (InnerList.Add(item))
{
return(true);
} else {
return(false);
}
}
}
I added the first condition to make my code actually work. It works as expected with this there. However, I can't understand why I would have to do this, and I can think of no reason, ever, why a HashSet would return "true" for Add() without adding anything. Even if my GetHashCode override is messed up, it should either add it and return true, or not and return false. Any thoughts?
Here's what I observed while debugging:
Breaking before InnerList.Add():
?InnerList.Count
1
?item.GetHashCode()
-1629834529
?InnerList.ElementAt(0).GetHashCode()
-1629834529
Step over the InnerList.Add(), which returns true:
?InnerList.Count
1
?InnerList.Add(item)
false
Wtf? This is .net 4.0 framework.
Your Add code is wrong:
public new virtual bool Add(TObject item)
{
// Must add parent first, since it may be used in the hash code
// InnerList is a HashSet<T>
if (InnerList.Any(existing=>item.GetHashCode()==existing.GetHashCode())) {
return(false);
} else {
if (InnerList.Add(item))
{
return(true);
} else {
return(false);
}
}
}
Two different items can have the same hash code! Your function should look like this:
public new virtual bool Add(TObject item)
{
return InnerList.Add(item);
}
I figure it out. This is a very insidious little thing. So the whole point of this setup is so that I can have collection classes that have a "Parent", and when you add items to the collection, they are automatically assigned that Parent. (This Parent is not simply the class itself, it's another object).
Here is the problem:
CsmResourceHashSet resources = new CsmResourceHashSet(Context);
resources.AddFrom(Context.ScriptResources
.Where(item=>item.Enabled));
CsmResourceHashSet is a ParentAwareHashset. Extension method AddFrom:
public static void AddFrom<T>(this ICollection<T> destList, IEnumerable<T> sourceList)
{
foreach (T obj in sourceList)
{
destList.Add(obj);
}
}
so it's apparently using the ICollection implementation to perform the Add. The void Add method of the base ParentAwareCollection is being used.
I guess it is casting my object to the base class when it uses this, even though I have a 'new Add. It seems weird to me that when you override a method with new, that an instance of that object could still have it's base method operated on externally.
#Anthony Pegram's comment actually enabled me to find the solution. So what was happening is that the void Add() was being called, which consequently called the actual derived InnerList Add(), which was indeed returning false, but that value was never getting back to code that needed to know about it.
The effect was that the HashSet actually had the correct contents, but Parent didn't get set for the one that got rejected from the HashSet. So this made the code work almost all the time... except when it mattered that the code didn't know something had been rejected. But without the "Equals" check, also, I was permitting duplicates of things that I shouldn't have been.
Solution was to add another ExtensionMethod for ISet<>
public static void AddFrom<T>(this ISet<T> destList, IEnumerable<T> sourceList)
{
foreach (T obj in sourceList)
{
destList.Add(obj);
}
}
Once I did that, it works. Well, actually it didn't work, but it revealed a couple crazy little bugs that mostly didn't manifest themselves, but all my exceptions started blowing up everywhere and it took no time to fix them all.

Categories

Resources