Can I define/constrain a member as implementing two interfaces, without generics? - c#

The following code shows what I would like to do; that is, I would like to constrain anObject, so that it can be used as a parameter to various methods with use IInterfaceOne or IInterfaceTwo, where neither inherits from the other.
public interface IInterfaceOne { }
public interface IInterfaceTwo { }
public class Implementation : IInterfaceOne, IInterfaceTwo
{
}
public interface IInterfaceOneAndTwo : IInterfaceOne, IInterfaceTwo { }
public class UsingImplementation
{
IInterfaceOneAndTwo anObject = (IInterfaceOneAndTwo)(new Implementation()); //fails because Implementation doesnt acctually implement IInterfaceOneAndTwo
}
This example fails however as IInterfaceOneAndTwo is an interface in its own right, and Implementation does not implement it.
I know if I used generics I could constrain them, but I am wondering, if there is a way to do this without generics?
Is there a way to say anObject shall implement IInterfaceOne and IInterfaceTwo, without using IInterfaceOneAndTwo?

Not the way you have it currently. Only generic constraints have that ability.
You could rewrite it to use generics:
public class UsingImplementation<T>
where T : IInterface1, IInterface2, new()
{
T anObject = new T();
void SomeMethod() {
anObject.MethodFromInterface1();
}
}

You can also have generic methods, not only generic classes
public void DoSomething<T>(T value)
where T : IInterface1, IInterface2
{
value.DoInterface1Things();
value.DoInterface2Things();
}
Or
public void DoSomething<T>()
where T : IInterface1, IInterface2, new()
{
T anObject = new T();
}

You can't do that in C# without generics but there is an alternative workaround to solve the problem without generics that was not mentioned here and might fit for you. This style is often used together with the IoC principle. You could inject the same object twice. Let me change your sample quite a bit...
public interface IInterfaceOne { void Hello(); }
public interface IInterfaceTwo { void World(); }
public class Implementation : IInterfaceOne, IInterfaceTwo
{
public void Hello() { };
public void World() { };
}
public class UsingImplementation
{
private readonly IInterfaceOne one;
private readonly IInterfaceTwo two;
public UsingImplentation(IInterfaceOne one, IInterfaceTwo two)
{
this.one = one;
this.two = two;
}
// do the stuff you want to do with an IInterfaceOne using field one
public DoSomeThingWithOne() { one.Hello(); }
// do the stuff you want to do with an IInterfaceTwo using field two
public DoSomeThingWithTwo() { two.World(); }
}
Then you could wire up the things this way:
var oneAndTwo = new Implementation();
var a = new UsingImplementation(oneAndTwo, oneAndTwo);
// operates on the first param (which is the same as the second)
a.DoSomeThingWithOne();
// operates on the second param (which is the same as the first)
a.DoSomeThingWithTwo();
Have a look for IoC principle (Inversion of Control) and Dependency Injection and you'll find more solutions similiar to this one.
This way you don't need to create an extra Interface combining InterfaceOne and InterfaceTwo, two.

"Incoming" generic class parameters and generic method parameters can combine types, but there is no facility for variables or fields to represent "composite" types. Further, in order to pass an object to a parameter of a generic type which combines multiple constraints, the object must be cast to a type which in fact implements all of those constraints. This can be difficult.
For example, suppose class Foo and Bar both implement Intf1 and Intf2. One wishes to write a function AddToList<T>(thing as T) where T:Intf1,Intf2. Such a function will perfectly happily accept objects of type Foo or Bar. Suppose, however, one wishes to use such a function to add all objects to the same list (which might be a mix of Foo, Bar, and any number of other types that also happen to implement Intf1 and Intf2) and then later pass those objects to a function whose parameter is likewise constrained to implement both Intf1 and Intf2. One could cast to Foo any object which happened to be a Foo, and cast to Bar any object which happened to be a Bar, but if other types are written which also handle Intf1 and Intf2, it would be difficult to deal with them.
It is possible to solve the problem, somewhat awkwardly, without using Reflection or other such tricks. Define an interface IActUpon<Base1, Base2> with a method ActUpon<thingType>ActUpon(thingType thing) where thingType: Base1, Base2. Implementations of such a method will be able to pass parameter thing to other methods requiring generic method parameter constrained to Base1 and Base2. The biggest difficulties with such an approach are that one must write separate code for each possible number of constraints, and that in many places where one would have used a lambda expression one will instead have to write an implementation of IActUpon....

If this is desirable then there has to be a logical connection between IInterfaceOne and IInterfaceTwo and the implementing class should implement the combined interface:
class Implementation : IInterfaceOneAndTwo { ... }
If this is not possible, because it's not (all) your code then you may have to rethink the UsingImplementation. It simply doesn't fit the available surface.

Related

'Strongly Typed' Generic Collections that hold any <T> of a given Interface/Class

Is it possible to declare a generic collection to hold only objects implementing a generic Interface with any <T>?
My question burns down to: If I want to/have to store objects implementing a generic interface, is there a better way to express that fact than using a non generic collection or (generic of <Object>).
Example:
// An example Generic Interface
interface ISyncInterface<T>
{
Task DoSync();
IEnumerable<T> NewItems { get; }
}
// a manager-class that registers different classes implementing
// the generic interface.
// The code works - can it be done better?
class Manager
{
private List<Object> _services = new List<Object>(); // <- works but is basically non generic
// however the RegisterService() ensures that only correct types can be added.
// would like to have something like below to indicate the Interface-Type
// however: this would only allow _services2.Add to hold types of ISyncInterface<Object>
// - ISyncInterface<ServiceA_DTO> would fail.
private List<ISyncInterface<Object>> _services2 = new List<ISyncInterface<Object>>();
void RegisterService<T, U>(T service)
where T : ISyncInterface<U>
{
_services.Add(service); // <- works e.g. for SyncServiceA
// _services2.Add(service); // <- FAILS for SyncServiceA - no conversion
// _services2.Add((ISyncInterface<Object>) service); // <- FAILS also - no explicit cast
}
}
// SETUP - The classes used above. Just to clarify.
class ServiceA_DTO { }
class ServiceB_DTO { }
class SyncServiceA : ISyncInterface<ServiceA_DTO>
{
public Task DoSync() {}
public IEnumerable<ServiceA_DTO> NewItems { get; }
}
class SyncServiceB : ISyncInterface<ServiceB_DTO>
{
public Task DoSync() {}
public IEnumerable<ServiceB_DTO> NewItems { get; }
}
Is this possible at all? Any advice is highly appreciated!
Update: New, more verbose code to clarify the problem.
Below there was a suggestion to base the generic interface on an non generic one. But as a consequence all implementing classes of the generic interface would have to implement the non generic methods, properties etc. - or is there a way around it?
Thanks for your input!
Is it possible to declare a generic collection to hold only objects implementing a generic interface instantiated with any T?
Short answer: no.
Longer answer: no, because that is not useful.
Let's consider a simple generic interface:
interface I<T> { T Get(); }
And a bunch of objects that implement it:
class Lion : I<Lion>
{
public Lion Get() => this;
}
class TaxPolicyFactory : I<TaxPolicy>
{
public TaxPolicy Get() => new TaxPolicy();
}
class Door: I<Doorknob>
{
public Doorknob Get() => this.doorknob;
...
}
OK, now suppose you have a List<I<ANYTHING>> like you want:
var list = new List<I<???>> { new TaxPolicyFactory(), new Lion(), new Door() };
You've got a list with a tax policy factory, a lion and a door in it. Those types have nothing in common with each other; there's no operation you can perform on each of those objects. Even if you could call Get on each of them, then you'd have a sequence with a tax policy, a lion and a doorknob in it, and what are you going to do with that?
Nothing, that's what. The constraint "implements interface I<T> for any T" is simply not a useful constraint in C#, so there is no way to express it.
It sounds like you have an "XY" problem. That is a problem where you have a bad solution in mind, and now you are asking questions about your bad solution. Ask us a question about the real problem you have, not the bad idea you've got for its solution. What's the real problem?
UPDATE: With the new information in the question it is now much more clear. The feature you want is called generic interface covariance, which was my favourite feature for C# 4.
If you update your interface definition to
interface ISyncInterface<out T> { ... }
then you can use an ISyncInterface<String> in a context where an ISyncInterface<Object> is expected. For example, you could put an ISyncInterface<Giraffe> into a List<ISyncInterface<Animal>> or whatever.
However you are required to ensure that your interface definition only uses T in a covariantly valid position. Your interface is valid as stated, but if for example you ever want to add a method void M(T t); to your interface, it will no longer be covariantly valid. The "out" is a mnemonic telling you that T can only be used as output of methods. Since IEnumerable<T> is also covariantly valid, it's fine; there are no inputs of T in an IEnumerable<T>.
Also, variance only works with generic interfaces and delegates, and the varying types must be reference types. You can't put an ISyncInterface<int> into a List<ISyncInterface<Object>> because int is not a reference type.
There are many posts on SO about covariance and contravariance; you should also read the Microsoft documentation. It can be a confusing feature. If you're interested in the historical details of how we designed and implemented the feature, see my blog.
Perhaps you can try something like this:
public interface MyInterface
{//methods common to all types
void FirstMethod();
}
public interface MyInterface<T> : MyInterface
{//methods specific to a type
void FirstMethod(T parameter);
}
public class MyClassThatHandlesAllInterfaces
{
private List<MyInterface> _allInterfacesT; //first interface in the chain
public void AddInterface<T>(MyInterface<T> ifToAdd)
{
_allInterfacesT.Add(ifToAdd); // <- this is what I'd like to do
}
}
I use this pattern quite often. Because I do not know all the details about your scenario it might not be suitable for you.
But it might help other people searching google.

C# Generics: cannot convert from 'concrete class' to 'interface' error

Trying to generate a generic queue of filters to be applied to an image (where in the example filter it uses OpenCVSharp.GaussianBlur, but making it generic so I can plugin any custom filter I create).
I am struggling a bit with the C# generics and intellisense is showing:
cannot convert from 'GaussianBlur' to 'IFilter
Intellisense is recommending changing the following line:
filters.Enqueue(filter);
by casting to the interface
filters.Enqueue((IFilter<IFilterParams>)filter);
however, my question is why is casting required when the concrete class implements the interface and requires it by the generics definitions or am I misunderstanding how to declare the classes using generics.
Current implementation code is as follows:
public class FilterTest
{
private FilterCollection filters = new FilterCollection();
/* ... other irrelevant code ... */
public void ApplyFilters(ref Mat buffer)
{
var filter = new GaussianBlur(new GaussianBlurParams { KernelSize = new Size(6, 6) });
filters.Enqueue((IFilter<IFilterParams>)filter);
filters.Apply(ref buffer);
}
}
.
I am extending the Queue<> class for the FilterCollection:
public class FilterCollection : Queue<IFilter<IFilterParams>>
{
public void Apply(ref Mat buffer)
{
while (Count > 0)
Dequeue().Apply(ref buffer);
}
}
and the interfaces for IFilter and IFilterParams are as follows:
public interface IFilter<T> where T : IFilterParams
{
void Apply(ref Mat buffer);
}
public interface IFilterParams { }
And then the sample filter implementation (more or less just a wrapper in this case):
public class GaussianBlurParams : IFilterParams
{
public Size KernelSize = new Size(5, 5);
public double SigmaX = default(double);
public double SigmaY = default(double);
public BorderTypes BorderType = BorderTypes.Default;
}
public class GaussianBlur : IFilter<GaussianBlurParams>
{
private GaussianBlurParams p;
public GaussianBlur(GaussianBlurParams filterParams)
{
this.p = filterParams;
}
public void Apply(ref Mat buffer)
{
Cv2.GaussianBlur(buffer, buffer, p.KernelSize, p.SigmaX, p.SigmaY, p.BorderType);
}
}
So given:
GaussianBlur implements IFilter<GaussianBlurParams>
and IFilter<T> where T : IFilterParams
and GaussianBlurParams implements IFilterParams
Is casting the only way to fix this or is there something wrong with the structure of the generic classes/interfaces as written?
There are multiple aspects to your code that get entangled here and that altogether make the design that less than optimal. At first glance this might look like an issue of covariance, but on a closer look this is not the case. The two main aspects here are generic constraints and interfaces. To understand what I mean, let's take a look at some of the benefits of these two language elements.
Generic constraints
While generics enable you to use an implementation of a pattern for multiple types in a type-safe way, there is not much you can do to directly manipulate an object of type T from within the generic class. You can not create an instance, you can not rely on instances being reference or value types (try a comparison with null to see what that means) and you can not access any other members than the ones defined in System.Object. That's why you can use generic constraints to allow code within the generic class that can do additional things with objects of type T, like creating instances (with the new() constraint) or access additional members (by constraining T to a certain type and/or one or more interfaces).
Interfaces
Interfaces provide a contractual guarantee that the implementer will have a defined set of members. This guarantee is directed to consumers of the interface, not to its implementers. That means that you don't use interfaces to force its implementer to provide some members that are not of any value to the consumer of the interface.
What this means in your case
The key to your problems is this part of your code:
public interface IFilter<T> where T : IFilterParams
{
void Apply(ref Mat buffer);
}
public interface IFilterParams { }
In particular:
You define the generic constraint where T : IFilterParams, but IFilterParams provides no members. This constraint adds no value to your design. You restrict the implementer to a certain T, but you don't gain anything from it, because you can't do anything with instances of T that you couldn't do without the constraint.
Going one step further, you don't need the interface to be generic at all. You don't even use T in the only member that the interface provides. You could do just fine without it as far as the guarantees of the interface are concerned.
Taking a look at the GaussianBlur implementation of IFilter<T>, it is clear that you use the GaussianBlurParams only in the constructor, which is not part of the interface. So you are using the constraint of the interface only to restrict the implementer to use a Params class that implements IFilterParams. That is not even a real restriction, because the implementer can use any other parameter class for its initialization. But mainly this violates the principle that the interface provides a guarantee to its consumers, not a restriction its implementers.
Putting this all together, you can simply go for...
public interface IFilter
{
void Apply(ref Mat buffer);
}
...and you have avoided all the problems you are facing.
Even if you would need T with the constraint where T : IFilterParams for another consumer of the interface (maybe there is another interface member that you have not added in your example), your FilterCollection does not need this constraint. So you can still keep a non-generic IFilter and provide another interface (that might or might not inherit from IFilter) that provides the additional capabilities.
Ok, thanks to #zzxyz's original comment along with the comments and answer that were added and then shortly after removed, lead me to research more on covariance (which I created by adding the generic IFilterParams in order to avoid covariance), and answers/comments in SO (Contravariance? Covariance? What's wrong with this generic architecture...?) helped me correct my problem and better structure the code.
Now I understand how I was trying to 'add a banana to a bowl(fruit) (fruit being the covariant as it is not just one 'type' of fruit) when I needed to be adding the banana to a bowl(bananas)'. I am understanding but quite poorly summing up one of the answers that were unfortunately deleted.
In researching, I was able to remove the covariance by creating an abstract class with its own generic type for the filterParams and removing the IFilterParams interface altogether, thus all filters must implement the base abstract class, and now no longer cause covariance.
Since I understand it now, but not well enough to explain (above) clearly, the revised code (below) may help explain better.
First, no changes to the FilterTest class were necessary (except removing the casting from the original example which was the point of the question):
public class FilterTest
{
private FilterCollection filters = new FilterCollection();
public void ApplyFilters(ref Mat buffer)
{
var filter = new GaussianBlur(new GaussianBlurParams { KernelSize = new Size(6, 6) });
filters.Enqueue(filter);
filters.Apply(ref buffer);
}
}
Next, adjusted the Queue so it was not covariant (implements one 'type' IFilter) which exposes the needed 'Apply' method.
public class FilterCollection : Queue<IFilter>
{
public void Apply(ref Mat buffer)
{
while (Count > 0)
Dequeue().Apply(ref buffer);
}
}
public interface IFilter
{
void Apply(ref Mat buffer);
}
And finally removed the IFilterParams as they are no longer relevant to the cause. Now the sample filter implementation looks like:
public class GaussianBlur : IFilter
{
private GaussianBlurParams p;
public GaussianBlur(GaussianBlurParams filterParams)
: base(filterParams)
{
}
public override void Apply(ref Mat buffer)
{
Cv2.GaussianBlur(buffer, buffer, p.KernelSize, p.SigmaX, p.SigmaY, p.BorderType);
}
}
public class GaussianBlurParams
{
public Size KernelSize = new Size(5, 5);
public double SigmaX = default(double);
public double SigmaY = default(double);
public BorderTypes BorderType = BorderTypes.Default;
}
Problem fixed, hopefully helps others!

Inferring C# Generic Type of Subclass

I have a generic class Proxy<T>, and I want to write another generic class with its type parameter being a Proxy.
I want to write:
public class MyClass<U> where U : Proxy<T>
but the compiler reports The type or namespace name T could not be found.
A solution I've found is to declare it like this:
public class MyClass<U, T> where U : Proxy<T>
but this seems clumsy as the client will have to declare two type parameters, like this:
public class SomeClass { ... }
public class SomeProxy : Proxy<SomeClass> { ... }
and then in a client somewhere:
var proxyWrapper = new MyClass<SomeProxy, SomeClass>();
How can I do this without having to have two generic types on MyClass. After all, if we know the first is SomeProxy, it should follow that the second is SomeClass.
Maybe something like this would do the job, too?
class Test<T> {
public Test(Proxy<T> proxy) { this.MyProxy = proxy; }
public Proxy<T> MyProxy { get; private set; }
}
Sorry, you just can't do this in C# without having MyClass generic on both types (unless you want to use reflection to create instances of it.)
You can have an interface IMyClass<SomeProxy> and a factory method that creates and returns an instance of MyClass<SomeProxy, SomeClass>. You may need to create the instance using Reflection.
I have a code example here of a similar situation: the end user only cares about a single type parameter, but the implementation needs to have two. In my example, I don't have to use Reflection to create the instance, but it sounds like you may need to.
What you're trying to do is possible using compile-time constructs such as C++ templates, but not run-time constructs such as C# generics.
If you want T to remain generic in Myclass, then the MyClass instance still needs to resolve all internally used generic types and you HAVE TO declare it somewhere. The way to go is the verbose way you mentioned:
public class MyClass<U, T> where U : Proxy<T>
If you don't care about the generic type T in MyClass then create interface and use it instead:
public interface IProxy { ... }
public class SomeClass { ... }
public class SomeProxy : Proxy<SomeClass>, IProxy { ... }
public class MyClass<U> where U : IProxy
and then in a client somewhere:
var proxyWrapper = new MyClass<SomeProxy>();
But do note that you cannot use type T in your interface declaration and Type U is now more general then before.
It turns out that all of the SomeProxy classes I want to deal with actually just override one method of Proxy<T> which has the signature:
T LoadInternal(Identifier id)
So, what I've done is created an internal class inside MyClass which takes a Func<Identifier, T> in its constructor. I can then pass a Func<Identifier, T> as a parameter to the constructor of MyClass and use my subclass in place of SomeProxy.
Seems a bit convoluted, but it works for me. To summarise, I now have:
public class MyClass<T>{
private SomeProxy theProxy;
public MyClass(Func<Identifier, T> loadDelegate){
theProxy = new SomeProxy(loadDelegate);
}
/* Other methods here */
class SomeProxy : Proxy<T>{
private Func<Identifier, T> m_loadInternal;
public SomeProxy(Func<Identifier, T> loadInternal){
m_loadInternal = loadInternal;
}
protected override T LoadInternal(Identifier id){
return m_loadInternal(id);
}
}
}
So, from client code, instead of writing a class which extends Proxy and then overriding LoadInternal in that class, I just create MyClass using:
var myClass = new MyClass<T>(x => CodeWhichReturnsT());
How can I do this without having to have two generic types on MyClass. After all, if we know the first is SomeProxy, it should follow that the second is SomeClass.
Although you seem to have found an answer to the main part of the question, I figured I'd offer my understanding about this part. It sounds like you wish you could do something like this:
class Proxy<T>
{
T Value { get; set; }
}
class MyClass<U> where U : Proxy<> { }
and have the compiler fill in the Proxy type parameter when you provide U. Since you have declared U as inheriting from Proxy, you must intend to use one of the methods on Proxy, that probably use the T parameter, like so:
class MyClass<U> where U : Proxy<>
{
void SomeMethod(U parameter)
{
var local = parameter.Value;
//more code here...
}
}
Now, what is the compiler supposed to infer for local here? This is the main problem I see that makes such a feature, if possible, hard to implement. If you don't want to use any methods that use the generic type of Proxy, you could instead make a non-generic base class and use that for U and sidestep the entire problem.
I am not a compiler writer, but a couple possibilities of how this could be dealt with come to mind. It could just say object (or whatever other restriction you put on the type parameter in Proxy), but that doesn't seem quite right or quite what normal generics seem to do. This would also require the CLR to allow open generic types as a constraint on the generic parameter, which I doubt it does. The other option I could see is for the type to actually have the second type parameter, and the compiler to give you syntactic sugar to make it easier.
Any way you go, this feature seems like a lot of work for a little benefit in what is probably a rare scenario, thus not likely to make the cut to get implemented.

Generic <T> how cast?

I have a "Product" base class, some other classes "ProductBookDetail","ProductDVDDetail" inherit from this class. I use a ProductService class to make operation on these classes. But, I have to do some check depending of the type (ISBN for Book, languages for DVD). I'd like to know the best way to cast "productDetail" value, I receive in SaveOrupdate. I tried GetType() and cast with (ProductBookDetail)productDetail but that's not work.
Thanks,
var productDetail = new ProductDetailBook() { .... };
var service = IoC.Resolve<IProductServiceGeneric<ProductDetailBook>>();
service.SaveOrUpdate(productDetail);
var productDetail = new ProductDetailDVD() { .... };
var service = IoC.Resolve<IProductServiceGeneric<ProductDetailDVD>>();
service.SaveOrUpdate(productDetail);
public class ProductServiceGeneric<T> : IProductServiceGeneric<T>
{
private readonly ISession _session;
private readonly IProductRepoGeneric<T> _repo;
public ProductServiceGeneric()
{
_session = UnitOfWork.CurrentSession;
_repo = IoC.Resolve<IProductRepoGeneric<T>>();
}
public void SaveOrUpdate(T productDetail)
{
using (ITransaction tx = _session.BeginTransaction())
{
//here i'd like ot know the type and access properties depending of the class
_repo.SaveOrUpdate(productDetail);
tx.Commit();
}
}
}
I don't mean to be critical, but that pattern just feels bad to me.
I've heard others say that if you're taking a type in a generic method, then you're most likely doing something wrong.
I would refactor your code by declaring a base class method to help with the SaveOrUpdate method, then have the derived classes override that method. Now when you call the base class method in the generic method, you will get the derived classes implmentation
Nooooo
If you have non generic properties (as specified in common interface contract) then you should have a common function declared in the interface that is called by SaveOrUpdate to handle this
Each instance of the common interface (ProductDetailBook, productDetail etc) will define this function differently as required by "//here i'd like ot know the type and access properties depending of the class"
You are pulling class specific code and putting it into a common function, this is the start of spaghetti code
This is one of the many reasons NOT to have generic services
If you need to know about the fields or properties of the type in order to "save or update", you could use reflection. That way, the class would remain truly generic.
If within your SaveOrUpdate method you mean to write an ever-expanding switch equivalent to:
if (it's type A) { deal with type A }
else if (it's type B) { deal with type B }
... and so on
Then you're doing it "wrong". That class is not really generic in its type parameter. It only works with the specific set of types you specified. I say "wrong" in quotes because it might be better than the available alternatives in some situations, but it's undesirable. If you have a fall-back for all other types, so it always works, then it might be an okay way to have special cases for certain types.
However, you can do such a test, or casting. With an unconstrained type parameter, T, you need to cast it to object first:
var eitherStringOrNull = (string)((object)somethingOfTypeT);
With the as keyword you shouldn't need that extra cast to object.
var eitherStringOrNull = somethingOfTypeT as string;
if (eitherStringOrNull != null)
{
.. it was a string, so we can use it as such
}
But even better, if there is a common base class, ProductDetail, for all kinds of product detail class, then use that as a constraint on T:
public class ProductServiceGeneric<T> : IProductServiceGeneric<T>
where T : ProductDetail
I think it's good practise when doing that to use a more meaningful name for the type parameter, such as TProductDetail.
If you do this, then the compiler should let you "cast down" to something derived from ProductDetail, without having to cast to object first.
If I understand your question you are trying to determine what derived class you have from a function that returns a base class. You need to use the IS operator
you can see how to use the operator below.
class Base
{
}
class AB : Base
{
}
class AC : Base { }
class Program
{
static Base GetObject()
{
return null;
}
static void Main(string[] args)
{
Base B = GetObject();
if (B is AB)
{
AB DevClass =(AB) B;
}
}
}
}
Within generic methods, you have to cast with as keyword to do casts like this. There are good reasons why but its a long story...
If you do a lot with generics, read Bill Wagners "More Effective C#" for alternative ways to dealing with this more cleanly.
public void SaveOrUpdate(T productDetail)
{
using (ITransaction tx = _session.BeginTransaction())
{
ProductDetailBook bookDetail = productDetail as ProductDetailBook;
if (bookDetail != null)
_repo.SaveOrUpdate(bookDetail);
tx.Commit();
}
}
Maybe you should refactor your code as follows:
abstract class Product
{
public abstract bool CheckProduct();
}
class ProductBookDetail : Product
{
public override bool CheckProduct()
{
//Here we can check ProductBookDetail
}
}
class ProductDetailDVD : Product
{
public override bool CheckProduct()
{
//Here we can check ProductDetailDVD
}
}
public class ProductServiceGeneric<T> : IProductServiceGeneric<T> where T : ProductDetail
{
public void SaveOrUpdate(T product)
{
if (!product.CheckProduct())
{
//product checking failes. Add necessary logic here
}
}
}
This code is much more appropriate for OOP. It much simpler, it more extensible and less error prone.
P.S. Don't forget about S.O.L.I.D.
I would look up Strategy pattern and maybe use that in conjunction with your generic repository. Then you can define your strategy in some interface for your entities, which forces them to implement some method like CheckConstraints. In your generic repository you then call CheckConstraints before executing SaveOrUpdate.
Use:
if(productDetail is ProductDetailBook)
{
...
...
}
and similarly for others.

Non Generic Versions of Generic classes and interfaces

I often find myself in a situation where I create a generic interface or class and then want to use different versions of this class or interface in a non generic way. For example I may have an interface like this:
interface ICanCreate<T>
{
T NewObject();
}
Which allows a class to be a factory for that type. I then want to register these with a general factory class, so I try to write something like this:
public class Factory
{
private Dictionary<Type, ICanCreate> mappings; // what do I put here????
public void RegisterCreator<T>(ICanCreate<T> creator)
{
}
public T Create<T>()
{
}
}
In the dictionary which type do I use for my value? I don't know if I am missing some sort of design principle and I am aware that this has a lot to do with co(ntra?)variance. Any help or ideas would be much appreciated.
You either have to just use object in your dictionary declaration (it's all private, and you can verify that you'll never put the wrong kind of thing in there) or declare a non-generic ICanCreate interface which ICanCreate<T> extends.
Basically you want a type relationship which can't be expressed in C# - and whenever that happens, you end up with a slightly unpleasant solution, but it looks like you can isolate the ugliness here (i.e. keep it within the single class).
Interestingly, this is a problem that is solved in C# 4.0:
public interface ICanCreate<out T> // covariant
{
T NewObject();
}
public class Factory
{
private Dictionary<Type, ICanCreate<object>> mappings = new Dictionary<Type, ICanCreate<object>>();
public void RegisterCreator<T>(ICanCreate<T> creator) where T:class
{
mappings[typeof(T)] = creator;
}
public T Create<T>()
{
ICanCreate<object> creator = mappings[typeof(T)];
return (T) creator.NewObject(); // I do not think you can get rid of this cast
}
}

Categories