Overloading generic methods - c#

When calling a generic method for storing an object there are occasionally needs to handle a specific type differently. I know that you can't overload based on constraints, but any other alternative seems to present its own problems.
public bool Save<T>(T entity) where T : class
{ ... some storage logic ... }
What I would LIKE to do is something like the following:
public bool Save<SpecificClass>(T entity)
{ ... special logic ... }
In the past our team has created 'one-off' methods for saving these classes as follows:
public bool SaveSpecificClass(SpecificClass sc)
{ ... special logic ... }
However, if you don't KNOW that function exists, and you try to use the generic (Save) then you may run into a host of problems that the 'one-off' was supposed to fix. This can be made worse if a new developer comes along, sees the problem with the generic, and decides he's going to fix it with his own one-off function.
So...
What are the options for working around this seemingly common issue?
I've looked at, and used UnitOfWork and right now that seems to be the only option that actually resolves the problem - but seems like attacking a fly with a sledgehammer.

You could do :
public bool Save<T>(T entity) where T : class
{ ... some storage logic ... }
public bool Save(SpecificClass entity)
{ ... special logic ... }
For example:
public class SpecificClass
{
}
public class Specializer
{
public bool GenericCalled;
public bool SpecializedCalled;
public bool Save<T>(T entity) where T : class
{
GenericCalled = true;
return true;
}
public bool Save(SpecificClass entity)
{
SpecializedCalled = true;
return true;
}
}
public class Tests
{
[Test]
public void TestSpecialization()
{
var x = new Specializer();
x.Save(new SpecificClass());
Assert.IsTrue(x.SpecializedCalled);
Assert.IsFalse(x.GenericCalled);
}
}

Well basicly C# does not allow template specialization, except through inheritence like this:
interface IFoo<T> { }
class Bar { }
class FooBar : IFoo<Bar> { }
At least it does not support this during compile time. However you can use RTTI to do what you are trying to achieve:
public bool Save<T>(T entity)
{
// Check if "entity" is of type "SpecificClass"
if (entity is SpecificClass)
{
// Entity can be safely casted to "SpecificClass"
return SaveSpecificClass((SpecificClass)entity);
}
// ... other cases ...
}
The is expression is pretty handy to do runtime type checks. It works similar to the following code:
if (entity.GetType() == typeof(SpecificClass))
// ...
EDIT : It is pretty common for unknown types to use the following pattern:
if (entity is Foo)
return DoSomethingWithFoo((Foo)entity);
else if (entity is Bar)
return DoSomethingWithBar((Bar)entity);
else
throw new NotSupportedException(
String.Format("\"{0}\" is not a supported type for this method.", entity.GetType()));
EDIT 2 : As the other answers suggest overloading the method with the SpecializedClass you need to take care if you are working with polymorphism. If you are using interfaces for your repository (which is actually a good way to design the repository pattern) there are cases where overloading would lead to cases in which you are the wrong method get's called, no matter if you are passing an object of SpecializedClass to the interface:
interface IRepository
{
bool Save<T>(T entity)
where T : class;
}
class FooRepository : IRepository
{
bool Save<T>(T entity)
{
}
bool Save(Foo entity)
{
}
}
This works if you directly call FooRepository.Save with an instance of Foo:
var repository = new FooRepository();
repository.Save(new Foo());
But this does not work if you are calling the interface (e.g. if you are using patterns to implement repository creation):
IRepository repository = GetRepository<FooRepository>();
repository.Save(new Foo()); // Attention! Call's FooRepository.Save<Foo>(Foo entity) instead of FooRepository.Save(Foo entity)!
Using RTTI there's only one Save method and you'll be fine.

Because function and operator overloads involving generics are bound at compile-time rather than run-time, if code has two methods:
public bool Save<T>(T entity) ...
public bool Save(SomeClass entity) ...
then code which tries to call Save(Foo) where Foo is a variable of some generic type will always call the former overload, even when the generic type happens to be SomeClass. My suggestion to resolve that would be to define a generic interface ISaver<in T> with a non-generic method DoSave(T param). Have the class that provides the Save method implement all of the appropriate generic interfaces for the types it can handle. Then have the object's Save<T> method try to cast this to an ISaver<T>. If the cast succeeds, use the resulting ISaver<T>; otherwise perform a generic save. Provided that the class type declaration lists all of the appropriate interfaces for the types it can save, this approach will dispatch Save calls to the proper methods.

Why using different names for your method?
See the following:
public class Entity
{
}
public class SpecificEntity : Entity
{
}
public class Program
{
public static void Save<T>(T entity)
where T : class
{
Console.WriteLine(entity.GetType().FullName);
}
public static void Save(SpecificEntity entity)
{
Console.WriteLine(entity.GetType().FullName);
}
private static void Main(string[] args)
{
Save(new Entity()); // ConsoleApplication13.Entity
Save(new SpecificEntity()); // ConsoleApplication13.SpecificEntity
Console.ReadKey();
}
}

Related

Cannot cast object of T to concrete type

I'm trying to understand generic types. However, I think I'm getting confused with fakes.
On my system, I'd like to load something. It doesn't matter what it is, and it could be anything. The caller will konw what it is.
My approach is to use an interface, where the interface is simply
public interface ILoad
{
void Load<T>(T t);
}
In my Bll class, I have a method which is
public void Start(ILoad load)
{
load.Load<Survey>(this); // I'm telling it the type and passing it the object
}
public class FakeLoadForSurvey : ILoad //this class knows about Survey
{
public void Load<T>(T t)
{
t = new Survey(); //fails
{
}
It fails with the following error message
Cannot implicity convert type Survey to T
I hope the above example is clear enough.
How do I tell C# that T is of type Survey (or any other type)?
public class FakeLoadForSurvey : ILoad //this class knows about Survey
If the class implementing the interface knows the type for T, then move T to the interface:
public interface ILoad<T>
{
void Load(T t);
}
public class FakeLoadForSurvey : ILoad<Survey>
{
public void Load(Survey t)
{
t = new Survey();
}
}
Do note however that this won't affect the argument passed to Load().
So if some code calls it like this:
var surveyLoader = new FakeLoadForSurvey();
Survey surveyToLoad = null;
surveyLoader.Load(surveyLoader);
Then surveyToLoad is still null after Load() returns. If you don't want that, pass it with ref.
This code looks bad from a design point of view, since you are mixing generics with statically defined types. If you use generics, you should go all the way:
public interface ILoad
{
void Load<T>(T t) where T : new();
}
public class FakeLoadForSurvey : ILoad
{
public void Load<T>(T t) where T : new()
{
t = new T();
}
}
I am not sure what your intention is with the parameter you define, but it loses scope after the method, so t will never of any use outside of the Load<T> method.
public void Load<T>(T t) where T: Survey, new()
{
t = (T) new Survey(); // should succeed
}
But with a void return and without ref on the parameter this function still won't do anything useful.

How could I show methods depending of the generic entity of a class?

I want to create methods that only will able to use if the generic type of a class is from a specific type.
For example, I have two abstract classes NamedEntity and KeyedEntity and I have a class which works with a generic type: MyClass<T>
I would like to create a method X on MyClass<T> which only will be able if the T is a NamedEntity and a method Y on MyClass<T> which only will be able if T is a KeyedEntity. If T is both, both methods will be shown.
I don't want to implement the method independently of the generic type and thrown an error if the type is not the correct type to use the method, but if this is the only way I will do.
If I could inherit from multiple classes it would be easy, but how C#only allow me to inherit from one class it is being hard to think about for me.
EDIT
I agree with all your points. I will try to explain better:
I have an abstract service class, which could work with all the database entities of my system.
All entities could have the "default" methods like "GetById(long id); Create(T entity); Update(T entity)" and it's possible because I am working with an ORM (Nhibernate).
I would like to create the method "GetByName" but not all of the entities have the property "Name", so it will be better if the method GetByName appears only for services which works with a Generic Type that force the entity to have the property "Name", this Generic Type should be the entity class, if I use interfaces (INamedEntity, IKeyedEntity) the problem continue being the same.
If I'm understanding you correctly, you are trying to achieve something like the following (non compilable code follows):
class MyClass<T>
{
public void X(T t) where T: NamedEntity { ... }
public void X(T t) where T: KeyedEntitiy { ... }
}
This won't compile You can not constrain T at method level, only at class level.
Ok. Constraining at top level seems useless, because you'd need to constrain to both NamedEntity and KeyedEntity which is self defeating, so let's constrain at method level:
class MyClass<T>
{
public void X<Q>(Q q) where Q: NamedEntity { ... }
public void X<Q>(Q q) where Q: KeyedEntitiy { ... }
}
Now this won't compile because constraints on generic type parameters are not part of a method's signature. The two methods X would essentially be the same overload and therefore the compiler will flag the second method with an error; method X already exists....
Also, you'd need to check that Q and T are actually compatible and this will only be possible at runtime, not at compile time...yuck!
Ok, then the only option seems to be overloading:
public X(NamedEntity entity) { ... }
public X(KeyedEntity entity) { ... }
Of course this is also far from safe at compile time; you still need to check that the right method is called for the actual type of T and this check can only be done at runtime. Yuck again...
Also, what happens if you have the following:
class Foo: NamedEntity, KeyedEntity { }
myClass.X(new foo()); //now what? What X is called?
This whole setup just seems completely off, you should rethink you approach or give more information on what exactly is it you are trying to achieve.
UPDATE Ok, all clearer now. The methods dont share the same name, thats a big difference!
Based on new info in your question, I would recommend the following approach:
public interface IKeyedIdentity
{
long Id { get; }
}
public interface INamedIdentity: IKeyedIdentity
{
string Name { get; }
}
public class MyClass<T> where T: IKeyedIdentity
{
public void Create(T entity) { ... }
public void Update(T entity) { ... }
public T GetById(long id) { ... }
public Q GetByName<Q>(string name)
where Q : T, INamedEntity
{ ... }
}
Here it makes sense to make the method generic itself because there is a relationship between T and Q you can leverage. This wasn't altogether clear before.
Downside, you have to explicitly supply Q in calls to GetName, I can't think of any compile time safe set up that would avoid this.
UPDATE #2: I think you have to take a step back and implement specialized MyClass<T>s that know how to deal with each expected entity type.
Consider the following code, it should give you enough ideas to implement a similar pattern in your particular scenario:
public static class EntityManagerProvider
{
public static EntityManager<Q> GetManager<Q>()
{
if (typeof(INamedIdentity).IsAssignableFrom(typeof(Q)))
return typeof(NamedEntityManager<>).MakeGenericType(typeof(Q)).GetConstructor(new Type[] { }).Invoke(new Type[] { }) as MyClass<Q>;
if (typeof(IKeyedIdentity).IsAssignableFrom(typeof(Q)))
return typeof(KeyedEntityManager<>).MakeGenericType(typeof(Q)).GetConstructor(new Type[] { }).Invoke(new Type[] { }) as MyClass<Q>;
return null;
}
public abstract class EntityManager<T>
{
public void Create(T entity) { ... }
public void Update(T entity) { ... }
public abstract T GetById(long id);
public abstract T GetByName(string name);
}
private class KeyedEntityManager<Q> : EntityManager<Q> where Q : IKeyedIdentity
{
public override Q GetById(long id) { return default(Q); }
public override Q GetByName(string name) { throw new NotSupportedException(); }
}
private class NamedEntityManager<Q> : EntityManager<Q> where Q : INamedIdentity
{
public override Q GetById(long id) { throw new NotSupportedException(); }
public override Q GetByName(string name) { return default(Q); }
}
}
Now you can do the following:
var myNamedFooManager = MyClassProvider.GetMyClass<NamedFoo>();
var namedFoo = myNamedFooManager.GetByName("Foo"); //I know this call is safe.
var myKeyedFooManager = MyClassProvider.GetMyClass<KeyedFoo>();
var keyedFoo = myNamedFooManager.GetById(0); //I know this call is safe.
Downside: if you need to interact with a given entity that is both keyed and named in either way, you'll have to use two distinct managers.

Repository Pattern with Generic interface and DI in EF

i have this existing code
public interface IRepository<T>
{
void Create(T obj);
T Retrieve(string key);
}
public class ItemRepository : IRepository<Item>
{
public void Create(Item obj)
{
//codes
}
public Item Retrieve(string key)
{
//codes
}
}
i would like to create a General class repository where i have to inject a type of IRepository to the constructor then use its own implementation of the methods. i already have an existing code but it is currently wrong
public class Repository
{
IRepository<T> action = null;
public Repository(IRepository<T> concreteImplementation)
{
this.action = concreteImplementation;
}
public void Create(T obj)
{
action.Create(obj);
}
}
the classes are from EF. if there is no work around for this what will be the best approach?
If I understand you correctly you want a single repository which can create or retrieve an object of any type by delegating to a type specific repository implementation?
How do you imagine this working? you defined this Repository class, but you have to create a concrete implementation of the actual repository in order to use it, and then still have to create an instance of Repository anyway. Why not just use the generic implementation you have to create anyway?
And what about your Retrieve method? How will this look in your Repository class? Will you just return Object? or will you make your method generic?
Anyway to answer your question, you could do this I suppose:
public class Repository
{
IRepository action = null;
public Repository(IRepository concreteImplementation)
{
this.action = concreteImplementation;
}
public void Create<T>(T obj)
{
action.Create(obj);
}
}
but you have to introduce a non generic interface as well, as you can't require an interface with a generic parameter in the constructor without specifying the generic type on the class.
public interface IRepository
{
void Create(object obj);
object Retrieve(string key);
}
Or possibly you could pass in the type into the Create method instead of having a generic parameter:
public class Repository
{
IRepository action = null;
public Repository(IRepository concreteImplementation, Type respositoryType)
{
this.action = concreteImplementation;
expectedType=repositoryType;
}
public void Create(Type type, Object obj)
{
if(type==expected && obj.GetType()==type)
{
action.Create(obj);
}
}
}
but both of these are terrible ideas. Just use the generics and create a repository per type, it'll be best in the long run
I think you might just be missing the definition of T in the context of the general repository class.
Try adding <T> to the it like this:
public class Repository<T>
{
...
}

Argument type matches this class

Consider the following:
public interface ITree<X>
{
...
ITree<X> Union(ITree<X> other);
...
}
The idea is that I'm going to implement several types of tree. However, the Union() method only works if you try to union two trees of the same type. The type signature above does not enforce this restriction, however.
So, my question is: How can I write a type signature for Union() such that the other argument must have the same type as this?
(Obviously I can do a dynamic run-time test and throw an exception if the types don't match. But I would much, much rather to check this at compile-time if it can be done...)
There isn't a particularly clean way of expressing this, this is a consequence of using interfaces, since there's no way to know the implementing type of ITree<X>. The best method is probably to create another class/interface which constrains the concrete tree type and does the operation(s) you require:
public interface ITreeUnion<T, X> where T : ITree<X>
{
T Union(T left, T right);
}
you'll then have to pass instances of this interface type to where you need to carry out the required operation.
If you really require Union to go on the interface you can use a recurring template:
public interface ITree<T, X> where T : ITree<T, X>
{
T Union(T other);
}
public class RedBlackTree<T> : ITree<RedBlackTree<T>, T>
{
public RedBlackTree<T> Union(RedBlackTree<T> other)
{
}
}
According to your requirment, you would need a generic declaration of Union().
interface
public partial interface ITree<X> {
T Union<T>(T other) where T: ITree<X>;
}
sample classes
public partial class TreeOfObject: ITree<object> {
public T Union<T>(T other) where T: ITree<object> {
return default(T); // sample only; shuold be implemented yourself
}
}
public partial class TreeOfInt: ITree<int> {
public T Union<T>(T other) where T: ITree<int> {
return default(T); // sample only; shuold be implemented yourself
}
}
test
public static partial class TestClass {
public static void TestMethod() {
var x=new TreeOfObject();
var y=new TreeOfInt();
var xx=x.Union(x);
var yy=y.Union(y);
var xy=x.Union(y); // won't compile
var yx=y.Union(x); // won't compile
}
}
Why do you need the interface then? Simply implement a Replace method on each implementation of a tree:
public class RedBlackTree<T> {
public RedBlackTree<T> Union(RedBlackTree<T> other) { ... }
}
public class SplayTree<T> {
public SplayTree<T> Union(SplayTree<T> other) { ... }
}
Since you're looking for compile-time safety when dealing with each implementation of ITree, I would argue you just need to deal with the concrete types. Of course, you could have an ITree<T> with other methods on it if you require.
Somehow, the following actually compiles:
public interface ITree<TSelf, TItem> where TSelf : ITree<TSelf, TItem>
{
TSelf Union(TSelf other);
// ...
}
public class AvlTree<TItem> : ITree<AvlTree<TItem>, TItem> {
public AvlTree<TItem> Union(AvlTree<TItem> other) {
return other;
}
}
Of course it's not particularly useful, since then you'd have to declare variables as ITree<AvlTree>, at which point you might as well not use the interface. With C# generics, the values of generic type parameters have to be known at some point to reify the generic type.

Keeping differently typed generic objects in one collection

I've been building a small access rules module for a project where every particular rule is reflected by a generic Rule<TEntity> object. The rule takes a delegate to execute a certain logic.
There is a RulesContext class that provides methods to check access to a certain entity "foo" like this:
rulesContext.CanIRead<Foo>(myFoo);
My intention was to store all rules build during a setup process into one collection. But every approach I tried lead to a dead end.
I thought of something like:
IDictionary<Type, Rule<object>> _rules = new Dictionary<Type, Rule<object>>();
and:
var fooRule = new Rule<Foo>(foo => foo.FullfillsACertainFooCriterion())
_rules.Add(typeof(Foo), fooRule);
The CanIRead implementation would make sure to use the dictionary properly:
public bool CanIRead<TEntity>(TEntity entity)
{
var rule = _rules[typeof(entity)];
return rule.CanIRead(entity);
}
But the compiler does not like this: Rule<Foo> cannot be assigned to a parameter of type Rule<object>. Which kind of makes sense since it would break the contract (which says that I can use the dictionary's methods with any object as parameter which does not hold true for the fooRule which only accepts Foo typed objects. - Liskov principle)
However I cannot think of a way to solve this. How could I store Rule objects with different types in one collection?
Can you do this:
[TestFixture]
public class ContraVariance
{
[Test]
public void TestNameTest()
{
var rules = new List<IRule<object>>(); //object is used just for demo here, probably some interface of yours is better
rules.Add(new Rule<A>());
rules.Add(new Rule<B>());
}
}
public class A { }
public class B { }
public class Rule<TEntity> : IRule<TEntity>
{
}
public interface IRule<out T>
{
}
If not I think you have to have a non-generic IRule or RuleBase (class)
The out keyword int the interface means that T is out only (Covariant) you can read about it here.
I guess that out will be a problem in your case, i suspect that the rules have methods with TEntity passed as arguments.
Instead of using IDictionary<Type, object> which could hold anything (e.g. DateTime) as a value in the dictionary, you could make the values strictly Rule objects
Here
namespace RuleConsole
{
class Program
{
static void Main(string[] args)
{
var context = new RulesContext();
var objA = new A();
var objB = new B();
context.AddRule<A>(new Rule<A>(objA));
context.AddRule<B>(new Rule<B>(objB));
Console.WriteLine(context.CanIRead<A>(objA));
Console.WriteLine(context.CanIRead<B>(objB));
Console.ReadKey();
}
}
public interface IRule { }
public interface IRule<T> : IRule { }
public class Rule<T> : IRule<T>
{
T _entity;
public Rule(T entity)
{
_entity = entity;
}
}
public class A { }
public class B { }
public class RulesContext
{
Dictionary<Type, IRule> _ruleDict= new Dictionary<Type, IRule>();
public void AddRule<TEntity>(Rule<TEntity> rule)
{
_ruleDict.Add(typeof(TEntity), rule);
}
public bool CanIRead<TEntity>(TEntity entity)
{
var rule = (IRule<TEntity>)_ruleDict[typeof(TEntity)];
//CanIRead implementation here
return rule != null;
}
}
}
That's inherently non-type-safe.
What do you want to happen if you write
_rules[typeof(Foor)].CanRead(new Bar());
You need to make a non-generic base class or interface to store in the dictionary.
Well, this is almost embarassing - but I think you've just helped me unblock my brain :-)
If the problem is that IDictionary<Type, Rule<object>> is too specific, IDictionary<Type, object> does the trick:
var fooRule = new Rule<Foo>(foo => foo.FullfillsACertainFooCriterion())
_rules.Add(typeof(Foo), fooRule);
(same as in the question, but compiles this time)
public bool CanIRead<TEntity>(TEntity entity)
{
var rule = (Rule<TEntity>)_rules[typeof(entity)];
return rule.CanIRead(entity);
}
The blocker in my brain was that I was thinking the more generic the type argument within Rule<...> was, the more objects should be allowed in the dictionary, but in this case it is the other way around: The more generic that argument is, the more specific the contract gets.
Take:
IDictionary<Rule<Foo>>
by replacing Rule by its base class object, the dictionary gets more generic. However, by replacing Foo by object, the whole thing actually gets more specialized!
The whole reason for that is that the type argument of Rule is used as an input parameter.
That's an important lesson...

Categories

Resources