Comparing a class that inherits an interface to an interface reference - c#

In my class ClassA : ISomeInterface i have:
public class ClassA : ISomeInterface {
Entity entity;
public void Test(){
if(entity.Target == this){}
}
}
With Target in entity defined as:
public class Entity {
public ISomeInterface Target {get; private set;}
}
My editor then gives me a warning:
Possible unintended reference comparison; to get a value comparison cast the LHS to type `Object`
Although it compiles, this is the first time I've had this warning. Should I not be comparing interface references like this?

As you already stated it is a warning not an error. And the warning tells you what the compiler really does and maybe your intentionnally guess what should happen is wrong.
So being said that, lets further dig what the problem could be. Here is some sample code (that what's being meant with please give an complete example):
using System;
public interface ISomeInterface
{
}
public class ClassA : ISomeInterface
{
public ClassA(int id)
{
Id = id;
}
public int Id { get; }
public ISomeInterface Entity { get; set; }
public static bool operator== (ClassA x, ClassA y)
{
return true;
}
public static bool operator!= (ClassA x, ClassA y)
{
return false;
}
public override bool Equals(object obj)
{
return true;
}
public override int GetHashCode()
{
return 72;
}
public void Test()
{
if (Entity == this)
{
Console.WriteLine("same");
}
else
{
Console.WriteLine("different");
}
}
}
public class Program
{
public static void Main()
{
var first = new ClassA(1);
var second = new ClassA(1);
first.Entity = second;
first.Test(); // writes "different"
}
}
As you can see the code implements the equality comparers and Equals(). All these methods are saying that all instance are the same, but the call in if(Entity == this) still tells that they are different.
This is the meaning of the warning and the root cause is, that an equality check of an interface always falls back to the implementation within the type object. And that implementation is ReferenceEquals(x, y).
So to avoid this warning and make your intention clear you should either explicitly write if(ReferenceEquals(Entity, this)) or implement a stand-alone class that implements IEqualityComparer<ISomeInterface> and use an instance of it if(new MyComparer().Equals(Enity, this)) (do not instantiate the comparer within the if statement in real code) to make your intentation of comparison obvious.

Related

Adapting a Class to an Interface when it implements all of the interface but doesn't declare the interface

Let the following interfaces :
interface IFoo
{
void Foo();
}
interface IBar
{
void Bar();
}
interface IFooBar : IFoo, IBar
{
// No extra required feature.
}
And the class :
class Booh : IFoo, IBar
{
public void Foo() { }
public void Bar() { }
}
I cannot use Booh as a IFooBar, despite Booh implementing everything required by IFooBar, because it does not officially implement it.
In order to allow the use of a Booh as a IFooBar without changing Booh to class Booh : IFooBar, I have thought (based on another SO question) about writing a wrapper :
class FooBar<T> : IFooBar where T : IFoo, IBar
{
public T Value { get; private set; }
public FooBar(T value)
{
Value = value;
}
public void Foo() { Value.Foo(); }
public void Bar() { Value.Bar(); }
}
The problem with that is that I can us as is !
For exemple, if I use this wrapper class as a dictionary key, it will use the reference of the wrapper instead of the reference of the wrapped object.
If I do : someDictionary.Add(new FooBar<Booh>(someBooh), whatever); and then someDictionary.Remove<Booh>(new FooBar(someBooh)); it will not remove the Booh I added in a first place, because I created two different wrappers, each of them having its own address.
To work around this, I have overriden / implemented some methods for equality checks and hash codes :
class FooBar<T> : IFooBar where T : IFoo, IBar
{
// Same as above...
public bool Equals(FooBar<T> other)
{
return Value.Equals(other.Value);
}
public override bool Equals(object obj)
{
var cast = obj as FooBar<T>;
if (null != obj && null == cast || obj == null)
{
return false;
}
return Value.Equals(cast.Value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
}
This supposedly causes the wrapped object reference be used by dictionaries, I haven't tested yet.
So, my question is : are there other methods I need to override and / or implement in order to cover most (if not all) use cases ? I want that wrapper to behave like it was the object being wrapped itself, not another object. Thank you !
EDIT : Maybe I could instead make this a struct and rely on auto-boxing to wrap the wrapper struct into an object that will delegate it's hash code and equality check methods to the structure and thus use the wrapped object reference ?
Yes, the 3 methods you've done is all you need. A dictionary allegedly relies mostly on the hashcode.
However your cast in Equals(object obj) will go wrong: it will cast a Booh to null. You want to test/cast both FooBar<T> and just plain T.
JetBrains Rider offer more or less this:
bool Equals(FooBar<T> other)
{
return EqualityComparer<T>.Default.Equals(Value, other.Value);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj is T) return Value.Equals(obj);
if (obj.GetType() != this.GetType()) return false;
return Equals((FooBar<T>) obj);
}
public override int GetHashCode()
{
return EqualityComparer<T>.Default.GetHashCode(Value);
}
Which passes these tests:
[Fact]
public void CanUseInDict()
{
var foobar= new Booh();
IFooBar[] foobars= new IFooBar[]{ foobar.AsIFooBar() };
Dictionary<IFooBar,string> ifoobars= new Dictionary<IFooBar, string>()
{
{ foobar.AsIFooBar(), foobar.GetType().Name}
};
Assert.Equal( foobar.GetHashCode(), new FooBar<Booh>( foobar ).GetHashCode());
Assert.True( foobar.AsIFooBar().Equals( new FooBar<Booh>( foobar ) ) , "Equals FooBar<Booh>");
Assert.True( ifoobars.ContainsKey( new FooBar<Booh>(foobar) ), "ContainsKey");
ifoobars.Remove(foobar.AsIFooBar());
Assert.Empty(ifoobars);
}
I can't quite see that use struct instead makes much difference either way. You still have to override the Equality members the same.
I added
static class BoohFooBarExt
{
public static IFooBar AsIFooBar<T>(this T value ) where T:IFoo, IBar => new FooBar<T>(value);
}

Casting to a generic interface [duplicate]

I have the following classes
public abstract class BaseViewPresenter { }
public abstract class BaseView<T> : UserControl
where T : BaseViewPresenter { }
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter> { }
I have a method that looks like this (simplified)
public BaseView<BaseViewPresenter> Resolve(BaseViewPresenter model)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
// Correctly creates BaseView object
var control = Activator.CreateInstance(viewType);
// Fails to cast as BaseView<BaseViewPresenter> so returns null
return control as BaseView<BaseViewPresenter>;
}
When I call this using an instances of LoginPresenter
var login = new LoginPresenter();
var ctl = Resolve(login);
The line Activator.CreateInstance(viewType) correctly resolves into a new instances of my LoginView, however control as BaseView<BaseViewPresenter> can't do the cast correctly so returns null.
Is there a way to correctly cast the control into BaseView<BaseViewPresenter> without using specific type generics?
Since LoginView inherits from BaseView<LoginPresenter>, and LoginPresenter inherits from BaseViewPresenter, I would assume there's a way to convert LoginView to BaseView<BaseViewPresenter>.
I am stuck with using .Net 3.5
This is a very frequently asked question. Let's rename your types:
abstract class Fruit { } // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { } // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> { } // was LoginView
Your question now is:
I have a BowlOfApples, which inherits from FruitBowl<Apple>. Why can I not use it as a FruitBowl<Fruit>? An apple is a fruit, so a bowl of apples is a bowl of fruit.
No, it isn't. You can put a banana in a bowl of fruit, but you can't put a banana in a bowl of apples, and therefore a bowl of apples is not a bowl of fruit. (And by similar argument, a bowl of fruit is not a bowl of apples either.) Since the operations you can legally perform on the two types are different, they cannot be compatible.
Here is a photo of StackOverflow legend Jon Skeet demonstrating this fact:
The feature you want is called generic contravariance, and it is supported only on interfaces and delegate types when the compiler can prove that the variance is safe, and when the varying type is a reference type. For example, you can use an IEnumerable<Apple> in a context where IEnumerable<Fruit> is needed because the compiler can verify that there is no way that you can put a Banana into a sequence of fruit.
Do a search on "C# covariance and contravariance" on this site or on the web and you'll find many more details about how this feature works. In particular, my series of articles on how we designed and implemented this feature in C# 4 starts here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx
I accepted Eric's answer since it provides a great explanation of why what I wanted wasn't possible, but I also thought I'd share my solution in case anyone else runs into this same problem.
I removed the generic type parameter from my original BaseView class, and created a 2nd version of the BaseView class that included the generic type parameter and specifics for it.
The first version is used by my .Resolve() method or other code that doesn't care about the specific types, and the second version is used by any code that does care, such as the implentation of a BaseView
Here's an example of how my code ended up looking
// base classes
public abstract class BaseViewPresenter { }
public abstract class BaseView : UserControl
{
public BaseViewPresenter Presenter { get; set; }
}
public abstract class BaseView<T> : BaseView
where T : BaseViewPresenter
{
public new T Presenter
{
get { return base.Presenter as T; }
set { base.Presenter = value; }
}
}
// specific classes
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter>
{
// Can now call things like Presenter.LoginPresenterMethod()
}
// updated .Resolve method used for obtaining UI object
public BaseView Resolve(BaseViewPresenter presenter)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
BaseView view = Activator.CreateInstance(viewType) as BaseView;
view.Presenter = presenter;
return view;
}
You're expecting to treat the type as being covariant with respect to the generic argument. Classes can never be covariant; you'd need to use an interface rather than (or in addition to) an abstract class to make it covariant with respect to T. You'd also need to be using C# 4.0.
My usual solution to this problem is to create an intermediary class that has access to the type-parametric class's methods through delegates. Fields can also be accessed through getters/setters.
The general pattern goes:
public abstract class Super {}
public abstract class MyAbstractType<T> where T : Super {
public MyGeneralType AsGeneralType() {
return MyGeneralType.Create(this);
}
// Depending on the context, an implicit cast operator might make things
// look nicer, though it might be too subtle to some tastes.
public static implicit operator MyGeneralType(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
public int field;
public void MyMethod1() {}
public void MyMethod2(int argument) {}
public abstract bool MyMethod3(string argument);
}
public delegate T Getter<T>();
public delegate void Setter<T>(T value);
public delegate void MyMethod1Del();
public delegate void MyMethod2Del(int argument);
public delegate bool MyMethod3Del(string argument);
public class MyGeneralType {
public Getter<int> FieldGetter;
public Setter<int> FieldSetter;
public MyMethod1Del MyMethod1;
public MyMethod2Del MyMethod2;
public MyMethod3Del MyMethod3;
public static MyGeneralType Create<T>(MyAbstractType<T> t) where T : Super {
var g = new MyGeneralType();
g.FieldGetter = delegate { return t.field; };
g.FieldSetter = value => { t.field = value; };
g.MyMethod1 = t.MyMethod1;
g.MyMethod2 = t.MyMethod2;
g.MyMethod3 = t.MyMethod3;
return g;
}
public int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
The above exemplifies getting all the methods and fields but normally I only need a few of them. This is a general solution to the problem and one could feasibly write a tool to generate these intermediary classes automatically, which I might at some point.
Try it here: https://dotnetfiddle.net/tLkmgR
Note that this is enough for all my cases, but you can be extra hacky with this:
public abstract class MyAbstractType<T> where T : Super {
// ... Same everything else ...
// data fields must become abstract getters/setters, unfortunate
public abstract int field {
get;
set;
}
public static implicit operator MyAbstractType<Super>(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
}
public class MyGeneralType : MyAbstractType<Super> {
// ... same constructors and setter/getter
// fields but only keep method fields
// that contain the method references for
// implementations of abstract classes,
// and rename them not to clash with the
// actual method names ...
public MyMethod3Del myMethod3Ref;
// Implement abstract methods by calling the corresponding
// method references.
public override bool MyMethod3(string argument) {
return myMethod3Ref(argument);
}
// Same getters/setters but with override keyword
public override int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
And there you go, now you can literally cast a MyAbstractType<Sub> where Sub : Super to a MyAbstractType<Super>, although it's no longer the same object anymore, but it does retain the same methods and data, it's sort of a complex pointer.
public class Sub : Super {}
public class MySubType : MyAbstractType<Sub> {
public int _field;
public override int field {
get { return _field; }
set { _field = value; }
}
public override bool MyMethod3(string argument) {
Console.WriteLine("hello " + argument);
return argument == "world";
}
}
public class MainClass {
public static void Main() {
MyAbstractType<Sub> sub = new MyAbstractType<Sub>();
MyAbstractType<Super> super = sub;
super.MyMethod3("hello"); // calls sub.MyMethod3();
super.field = 10; // sets sub.field
}
}
This isn't as good in my opinion, the other version of MyGeneralType is a more straighforward layer over the concrete types, plus it doesn't require rewriting the data fields, but it does actually answer the question, technically. Try it here: https://dotnetfiddle.net/S3r3ke
Example
Using these abstract classes:
public abstract class Animal {
public string name;
public Animal(string name) {
this.name = name;
}
public abstract string Sound();
}
public abstract class AnimalHouse<T> where T : Animal {
List<T> animals;
public AnimalHouse(T[] animals) {
this.animals = animals.ToList();
}
public static implicit operator GeneralAnimalHouse(AnimalHouse<T> house) {
return GeneralAnimalHouse.Create(house);
}
public List<string> HouseSounds() {
return animals.Select(animal => animal.Sound()).ToList();
}
}
We make this "general" variant:
public delegate List<string> HouseSoundsDel();
public class GeneralAnimalHouse {
public HouseSoundsDel HouseSounds;
public static GeneralAnimalHouse Create<T>(AnimalHouse<T> house) where T : Animal {
var general = new GeneralAnimalHouse();
general.HouseSounds = house.HouseSounds;
return general;
}
}
And finally with these inheritors:
public class Dog : Animal {
public Dog(string name) : base(name) {}
public override string Sound() {
return name + ": woof";
}
}
public class Cat : Animal {
public Cat(string name) : base(name) {}
public override string Sound() {
return name + ": meow";
}
}
public class DogHouse : AnimalHouse<Dog> {
public DogHouse(params Dog[] dogs) : base(dogs) {}
}
public class CatHouse : AnimalHouse<Cat> {
public CatHouse(params Cat[] cats) : base(cats) {}
}
We use it like this:
public class AnimalCity {
List<GeneralAnimalHouse> houses;
public AnimalCity(params GeneralAnimalHouse[] houses) {
this.houses = houses.ToList();
}
public List<string> CitySounds() {
var random = new Random();
return houses.SelectMany(house => house.HouseSounds())
.OrderBy(x => random.Next())
.ToList();
}
}
public class MainClass {
public static void Main() {
var fluffy = new Cat("Fluffy");
var miu = new Cat("Miu");
var snuffles = new Cat("Snuffles");
var snoopy = new Dog("Snoopy");
var marley = new Dog("Marley");
var megan = new Dog("Megan");
var catHouse = new CatHouse(fluffy, miu, snuffles);
var dogHouse = new DogHouse(snoopy, marley, megan);
var animalCity = new AnimalCity(catHouse, dogHouse);
foreach (var sound in animalCity.CitySounds()) {
Console.WriteLine(sound);
}
}
}
Output:
Miu: meow
Snoopy: woof
Snuffles: meow
Fluffy: meow
Marley: woof
Megan: woof
Notes:
I added names so it's clear that the method references carry their owner's data with them, for those unfamiliar with delegates.
The required using statements for this code are System, System.Collections.Generic, and System.Linq.
You can try it here: https://dotnetfiddle.net/6qkHL3#
A version that makes GeneralAnimalHouse a subclass of AnimalHouse<Animal> can be found here: https://dotnetfiddle.net/XS0ljg

use a generic type as parameter in C#

is there a method to tell a method which type a generic has? what i want to do is to tell the method it can be only an object of type A or B but nothing else, so i can work within like
if (myObject.GetType() == typeof(myTypeA)){doAstuff();}
if (myObjectGetType() == typeof(myTypeB)) {doBstuff();}
method<T>(T myObject){ T = myTypeA, T = myTypeB, T = nothing else}
thanks for any help
You could check for the type inside the method, then cast it to the appropriate type and do the appropriate "stuff":
public void method<T>(T myObject)
{
if (myObject is myTypeA)
{
myTypeA objA = myObject as myTypeA;
objA.DoA_Stuff();
}
else if (myObject is myTypeB)
{
myTypeB objB = myObject as myTypeB;
objB.DoB_Stuff();
}
else
{
return ;
}
}
But that would be a waste of generics. If they share some methods you could also make a base class, and let typeA and typeB inherit from it. Then your method could take a base class object as parameter:
public void method(BaseClass myObject)
and there would be only one if - case and one casting. Only the one with more methods then the base class.
EDIT:
Imagine you would have such a structure:
public class BaseType
{
public int SharedProp { get; set; } // shared property
public virtual int DoSharedStuff() // shared method
{
return SharedProp;
}
}
public class myTypeA : BaseType
{
public int A_Prop { get; set; }
// overwritten shared meth adjusted to the needs of type A
public override int DoSharedStuff()
{
return base.SharedProp + this.A_Prop;
}
}
public class myTypeB : BaseType
{
public int B_Prop { get; set; }
// overwritten shared meth adjusted to the needs of type B
public override int DoSharedStuff()
{
return base.SharedProp + this.B_Prop;
}
// individual method of Type B
public int DoB_Stuff()
{
return this.B_Prop;
}
}
Then you method would take only one of the children of the base class and execute according to the needs:
public void method(BaseType myObject)
{
// shared case: here type A will perform type A action
// and type B will perform type B action
myObject.DoSharedStuff();
// case B where you need really the extra stuff!
if (myObject is myTypeB)
{
myTypeB objB = myObject as myTypeB;
objB.DoB_Stuff();
}
}
This approach or phenomenon is called Polymorphism
You can restrict the allowed types for a gernic with the where command:
public void Test<T>(T param) where T : TypeA {
...
}
https://learn.microsoft.com/de-de/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
But this are only simple constraints so it does not solve the problem for two classes but for this case you can use method overloading:
public void Test(TypeA param) {
...
}
public void Test(TypeB param) {
...
}
If you have only two classes I think that is the best solution because generics would have no benefits.

Avoid copying & pasting of almost generic code in subclasses

I currently have a class which encapsulates a list of typed objects and implements some interfaces like IEnumerable. I need a second class with additional, slightly different properties. So I will be creating a base class A and derive new class B and new class C from A.
However I have code (e.g like code for .Find using Delegates) which is almost the same in B and C. The only difference is that the code in B searches the private list of typed objects (let's say Person) and the code in C searches a private list of different objects (let's say Animal):
private static bool Find(Person xx)
{
if (xx.Id == someID)
{
return true;
}
else
{
return false;
}
}
As I want to avoid copying/pasting, my question is: What is a good strategy to avoid something like that?
The only way I imagined was to declare a list of generic objects in A and point the methods in A to that. In B and C I would then not have any code, however I lose all benefits of a typed list.
1) I would see if I could use generics when coding class A
public class cA<T>
{
private IEnumerable<T> _myPrivateData
public bool Find(args)
{
// Do stuff with _myPrivateData
}
}
public class cB : cA<TheTypeIWant>
{
// more stuff here if needed
}
2) You can use the property override feature + the use of the protected access modifier to do the following:
public class cA
{
protected IEnumerable<Object> MyData { get; set; }
public bool Find(args)
{
// Do stuff with MyData
}
}
public class cB : cA
{
protected new IEnumerable<MyOtherDataType> MyData { get; set; }
}
Of course MyOtherDataType has to inherit from the base type used for this approach to be possible. I would really not recommend this approach though. Option 1 is much better and cleaner.
Here's a few references that may prove to be useful:
http://peisker.net/dotnet/covariance.htm
C#: Overriding return types
I'd be tempted to have an interface like ICanBeFoundById
public interface ICanBeFoundById
{
int Id {get;}
}
then Person and Animal can both inherit from that and you can do something like
public static class FindExtensions
{
public static bool Find(this IEnumerable<ICanBeFoundById> xs, int someID)
{
return xs.Any(x=>x.Id == someID)
}
}
Warning: I haven't even checked if this compiles :)
Of course you could have some
public abstract class BaseRepository<ICanBeFoundById>
{
private IEnumerable<ICanBeFoundById> _xs;
public static bool Find(int someID)
{
return xs.Any(x=>x.Id == someID)
}
}
if you don't want to have a static extension.

Getting warning, 'Type Parameter X Hides Interface X'

This is occurring in Visual Studio 2010.
I'm working with generic methods, and basically losing my intellisense and stopping me from continuing work on this project.
I basically have the following class:
public class SearchRepository : DataRepository<IAudit>
{
public override IEnumerable<IAudit> RetrieveAll<IAuditSearch>(IAuditSearch searchParameters)
{
// CODE GOES HERE
}
public override bool Delete<TIAudit>(IAudit audit)
{
// CODE GOES HERE
}
}
This inherits from:
public abstract class DataRepository<T>
{
public virtual IEnumerable<T> RetrieveAll<U>(U parameter1)
{
throw new NotImplementedException();
}
public virtual bool Delete<U>(U parameter1)
{
throw new NotImplementedException();
}
}
So Delete works exactly how I would expect it to work. I have intellisense and it compiles correctly. RetrieveAll doesn't work correctly using IAuditSearch. If I change it to TIAuditSearch, then it says I'm "There is no suitable method to override".
Not sure what I'm doing wrong, but it's definitely not happy with me.
UPDATED: changed the virtual to override for the Delete method at the top. That was a mistake.
You are implicitly hiding (by not overriding) the method signature of
bool Delete<myType>(myType param) { ... }
You can overcome the error my introducing the "new" keyword on the derived class's Delete property. This explicitly hides the signature and makes everyone happy as it illustrates your intent.
Read the Microsoft documentation at: http://msdn.microsoft.com/en-us/library/aa691135%28v=vs.71%29.aspx.
You can't define the method public override IEnumerable RetrieveAll(IAuditSearch searchParameters)
The method must still use the U type parameter in place of IAuditSearch. Its up to the caller to choose what type to pass.
You'll probably need to create an ISearch interface and on the base class add where U : ISearch, but even then your subclass would need to accept all ISearch implemenations, not just IAuditSearch.
Probably the best solution is to define an IAuditSearch repository which is what defines your RetreiveAll method.
EDIT: I see the question has changed. You now have the same problem on both methods; you cannot dictate which interface to use when overriding the method, you must maintain the generic type parameter.
public override IEnumerable<T> RetrieveAll<U>(U parameter1) { }
public override bool Delete<U>(U parameter1) { }
Note that you cannot add where clauses to the methods either; this breaks the Liskov Substitution Prinicple. Also I'm not even sure the compiler would allow you to do that.
Would the following code work instead?
public class SearchRepository : DataRepository<IAudit, IAuditSearch>
{
public override IEnumerable<IAudit> RetrieveAll<IAuditSearch>(IAuditSearch searchParameters)
{
// CODE GOES HERE
}
public override bool Delete<TIAudit>(IAudit audit)
{
// CODE GOES HERE
}
}
public abstract class DataRepository<T, TSearch>
{
public virtual IEnumerable<T> RetrieveAll(TSearch parameter1)
{
throw new NotImplementedException();
}
public virtual bool Delete(T parameter1)
{
throw new NotImplementedException();
}
}
So for every instantiation of DataRepository, we declare the result type (T), and the search type (TSearch).
-C
Unfortunately, the exact context is not quite clear to me, but I believe your code should look like this:
public interface IParameter<T> {
bool Match(T entry);
}
public abstract class DataRepository<T, TParameter>
where TParameter : IParameter<T> {
public abstract IEnumerable<T> RetrieveAll(TParameter parameter1);
public abstract bool Delete(TParameter parameter1);
}
//
public interface IAudit {/* ... */}
public interface IAuditSearch : IParameter<IAudit> {/* ... */}
public class SearchRepository : DataRepository<IAudit, IAuditSearch> {
public override bool Delete(IAuditSearch parameter1) {
// iterate by collection items using parameter matching
// CODE GOES HERE (DELETE ALL FOUND ENTRIES)
}
public override IEnumerable<IAudit> RetrieveAll(IAuditSearch parameter1) {
// iterate by collection items using parameter matching
// CODE GOES HERE (RETURN ALL FOUND ENTRIES)
}
}
Different IAuditSearch implementation will incapsulate a "search by different parameter" logic:
var guidSearchResult = repository.RetrieveAll(
new GuidSearch(new Guid("00000000-0000-0000-0000-000000000000")));
var idRangeSearchResult = repository.RetrieveAll(
new IDRangeSearch(1000, 2000));
where GuidSearch and IDRangeSearch are implemented as:
public class GuidSearch : IAuditSearch {
Guid ID;
public GuidSearch(Guid id) {
this.ID = id;
}
public bool Match(IAudit entry) {
/* search implementation using ID(Guid)*/
throw new NotImplementedException();
}
}
public class IDRangeSearch : IAuditSearch {
int StartID;
int EndID;
public IDRangeSearch(int startId, int endId) {
this.StartID = startId;
this.EndID = endId;
}
public bool Match(IAudit entry) {
/* search implementation using ID range (StartID...EndID)*/
throw new NotImplementedException();
}
}

Categories

Resources