Generic class with non-generic method constraint? - c#

I have this class working as my repository:
public class Repository<T> where T : class, new()
{
public T GetByID(int id)
{
//Code...
}
}
But there a few cases where I don't want to leave a class' default public constructor (such as some specific model properties that require some logic), like this:
public class Person
{
public CPersonID PersonID { get; private set; }
//This shouldn't exist outside Person, and only Person knows the rules how to handle this
public class CPersonID
{
internal CPersonID() { }
}
}
This makes the Repository template class invalid because of the new() constraint.
I'd like to make something like this:
public class Repository<T> where T : class
{
//This function should be created only when the T has new()
public GetByID(int id) where T : new()
{
}
//And this could be the alternative if it doesn't have new()
public GetByID(T element, int id)
{
}
}
Is there any way I can accomplish this?
Edit: Example of a Get method:
public IList<T> GetAll()
{
IList<T> list = new List<T>();
using(IConnection cn = ConnectionFactory.GetConnection())
{
ICommand cm = cn.GetCommand();
cm.CommandText = "Query";
using (IDataReader dr = cm.ExecuteReader())
{
while(dr.Read())
{
T obj = new T(); //because of this line the class won't compile if I don't have the new() constraint
//a mapping function I made to fill it's properties
LoadObj(obj, dr);
list.Add(obj);
}
}
}
return list;
}

As Lasse V. Karlsen already answered, this is not directly possible. However, you can get very close, close enough for practical purposes.
Given public class Repository<T> where T : class, you cannot define instance methods that only exist when T has a parameterless constructor. You don't need that. You just need repository.GetByID(3) to work. That can work if GetByID is an instance method, but also if it is an extension method, and extension methods can add requirements to T.
public static class RepositoryExtensions
{
public T GetByID(this Repository<T> repo, int id) where T : class, new()
{
...
}
}
Note that extension methods don't work if an instance method of the same name already exists, so if you go with this, you need both overloads of GetByID to be extension methods, not just this one.
The actual logic belongs in the Repository class, but you can forward to that:
public class Repository<T> where T : class
{
internal T GetByIDImpl(int id, Func<T> factory)
{
...
}
}
public static class RepositoryExtensions
{
public T GetByID(this Repository<T> repo, int id) where T : class, new()
{
return repo.GetByIDImpl(id, () => new T());
}
public T GetByID(this Repository<T> repo, T element, int id) where T : class
{
return repo.GetByIDImpl(id, () => element);
}
}

No, you can't do it this way.
All constraints have to be specified the place where you introduce the generic parameter, in this case at the class level.
As such you have two options:
Add , new() as a constraint, limiting the use of the repository class to use types that have a public parameterless constructor
Not add it as a constraint, and use reflection to try to construct the object at runtime
Note that point 2 there may fail (at runtime) if the type does not have a valid constructor.
There is no way you can ask the compiler to create a class where the ability to call a specific method is conditional, ie. "Only let me call GetByID if the type has a constructor".

If you want it as a compile-time constraint, you can do
public class Class<T> where T : class
{
public void Method<U> where U : T, new()
{
// ...
}
}
but this has the disadvantage that you'd have to do
new Class<HasConstructor>().Method<HasConstructor>();
as the type won't be implicitly picked up. The advantage is that the following won't compile:
new Class<NoConstructor>().Method<NoConstructor>();

Related

What is the best way to call a method defined inside an abstract generic class from a non generic class

I don't want to make class B generic because there lots classes inheriting from class B. How to use the method "GetSomeData" of the generic class "classA" in a non generic class?
Here's my code:
public abstract class classA<T> : IInterface<T>
where T : new()
{
public String GetSomeData (Guid ID)
{
return somestring;
}
}
public abstract class ClassB : InterfaceB
{
//Use GetSomeData(Guid ID) here
}
what is the best way to invoke GetSomeData in class B?
First of all, your code doesn't look clean itself. C# coding conventions are not met & not all the components that are used present.
But to anser your question, you need to specify the concrete type T before using generic methods/classes.
For example working code may look like this:
public abstract class GenericParent<T>
where T : new()
{
public string GetSomeData(Guid id) => string.Empty;
}
// Non abstract type, to create be able to create an instance
public class GenericChild<T> : GenericParent<T> where T : new()
{
}
public abstract class ClassB
{
public void DoSomething()
{
// Creating instance of a generic type, specifying concrete T (in this case of type SomeClass)
var instance = new GenericChild<SomeClass>();
instance.GetSomeData(Guid.Empty);
}
}
// An example of type, that meets the "where" condition of T in the generic type
public class SomeClass
{
}
As per OOP principals Abstract classes can not be instantiated.
They could only be Inherited. Well there are couple of ways how you can access the instance variables and methods from the Abstract class as follows.
Make a sub-class inheriting the Abstract class; Create an object of sub-class and access all the Instance Variables and Methods.
public abstract class classA<T> : IInterface<T>
where T : ITask, new()
{
public String GetSomeData (Guid ID)
{
return somestring;
}
}
public class ChildOfClassA : ClassA<SomeType_of_Type_ITask>
{
}
public abstract class ClassB : InterfaceB
{
//Use GetSomeData(Guid ID) here
ChildOfClassA obj = new ChildOfClassA();
string result = obj.GetSomeData(Guid.NewGuid());
}
Make that method Static if its not tightly coupled to instance of the class. and then you can use it with ClassName.MethodName
public abstract class classA<T> : IInterface<T>
where T : ITask, new()
{
public **static** String GetSomeData (Guid ID)
{
return somestring;
}
}
public abstract class ClassB : InterfaceB
{
//Use GetSomeData(Guid ID) here
string result = classA.GetSomeData(Guid.NewGuid());
}
You can inherit this Abstract class in the class you want to use it and directly access it by base.MethodName or directly MethodName.
public abstract class classA<T> : IInterface<T>
where T : ITask, new()
{
public string GetSomeData (Guid ID)
{
return somestring;
}
}
public abstract class ClassB : ClassA<SomeType_of_Type_ITask>, InterfaceB
{
//Use GetSomeData(Guid ID) here
string result = [base.]GetSomeData(Guid.NewGuid()); //[base.] is optional even you can override this function or overload it.
}
In case 1 and 3 you will have to pass generic argument in order to inherit the Abstract class as in your case Abstract class accepts generic arguments.

Generic type vs Extension method

I need to make a comparison between two techniques : Use of generic type and extend type. I don't mean a general comparison, I mean in this specific case when I need to add some features to a class named ClassA
Using a generic type
use a generic type ( Where T: ClassA ) and implement generic methods
Using Extension Methods
Use the ClassA by adding its extension methods
public static class Helper
{
public static void MethodOne(this ClassA obj, )
{
//
}
}
I need to know :
What are the advantages of each technique in comparison with the other?
Why the first technique is always used in Repository Pattern? For example in this implementation why we don't add extension methods to a global class Entity ?
Those are two entirely different things.
You use generics to provide generic functionality. For repositories, this is often used with a "base entity" class or interface containing properties that all entities implement, like ID:
public interface IEntity
{
int ID { get; set; }
}
public class Client : IEntity
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Repository<T>
where T : IEntity
{
private readonly IQueryable<T> _collection;
public Repository(IQueryable<T> collection)
{
_collection = collection;
}
public T FindByID(int id)
{
return _collection.First(e => e.ID == id);
}
}
You could do that as well with an extension method:
public static T FindByID(this IQueryable<T> collection, int id)
where T : IEntity
{
return collection.First(e => e.ID == id);
}
Without generics, you'd have to implement the repository or the extension method for every type.
Why not use an extension method in this case: you generally only use those when you can't extend the base type. With the repository class you can group operations in one logical class.
See also When do you use extension methods, ext. methods vs. inheritance?, What is cool about generics, why use them?.

Assigning implementation of a generic interface to a property

I have an interface
public interface IStrategy<T> where T : BaseModel
{
T GetModel(Guid userId);
}
and a concrete class inheriting the interface specifying that it should be a ConcreteModel
public class ConcreteStrategy: IStrategy<ConcreteModel>
{
ConcreteModel GetModel(Guid userId) { ... }
}
Now in the following method I can pass a new instance of ConcreteStrategy and everything works
public class Manager
{
public TModel GetContentModel<TModel>(IStrategy<TModel> strategy, Guid userId)
where TModel : ModelBase
{
return strategy.GetContentModel(userId);
}
}
But if I try to assign it to a property like this I get an error
public class Strategies
{
public static IStrategy<ModelBase> MyStrategy { get; set; }
}
Strategies.MyStrategy = new ConcreteStrategy();
Is there a way I can achieve this in C# ?
I want to be able to make a factory method that encapsulates the logic for which strategy to use and just return an instance of some type of strategy class (like ConcreteStrategy).
The error I am getting is:
Cannot implicitly convert type IStrategy<ModelBase> to IStrategy<ConcreteModel>
You need to make your interface covariant:
public interface IStrategy<out T> where T : BaseModel
Note that it will work only if T only appears in an output position in the interface (which is the case in the code you have shown, but I don't know if it's your real code).

C# How to make a factory method return of the subclass type

[MAJOR EDITS, my first post was somewhat misleading. My appologies]
Given a class such as:
public class DatabaseResult{
public bool Successful;
public string ErrorMessage;
//Database operation failed
public static DatabaseResult Failed(string message) {
return new DatabaseResult{
Successful = true,
ErrorMessage = message
};
}
}
How can I implement subclasses such that I can add additional properties to represent data relevant to the particular operation (such as MatchedResult in the case of a SELECT type query) without the need to implement that static failure function? If I try to use plain inheritance, the return type will be of the parent class. Eg:
DoThingDatabaseResult : DatabaseResult {
public IEnumerable<object> SomeResultSet;
public static Successful(IEnumerable<object> theResults){
return new DoThingDatabaseResult {
Successful = true,
ErrorMessage = "",
SomeResultSet = theResults
};
}
//public static DatabaseResult Failed exists, but it's the parent type!
}
The goal is to avoid needing to copy the Failed static function for every subclass implementation.
Make it recursively generic:
public class BankAccount<T> where T : BankAccount<T>, new()
{
public T SomeFactoryMethod() { return new T(); }
}
public class SavingsAccount: BankAccount<SavingsAccount>{}
You'll note that I made the factory method non-static, because static methods aren't inherited.
You can't do this exactly as you have defined the question. The best way to tackle this is really to pull your factory out of the class completely:
public class BankAccount
{
}
public class SavingsAccount : BankAccount
{
}
public static class BankAccountFactory
{
public static T Create<T>() where T : BankAccount, new()
{
return new T();
}
}
Now the Factory has no dependency on the actual type. You can pass any derived class of BankAccount and get it back without doing any extra work or worrying about inheriting your factory method.
If I may, I'd like to expand upon StriplingWarrior. In fact, you can use static for the factory. This following code shows that a and c are the expected object types. The limit is you cannot use the factory on the base class itself.
private void Testit()
{
var a = SavingsAccount.Factory();
var c = CheckingAccount.Factory();
//var b = BankAccount.Factory(); //can't do this
}
public class BankAccount<T> where T : BankAccount<T>, new()
{
public static T Factory()
{
return new T();
}
}
public class SavingsAccount : BankAccount<SavingsAccount>
{
}
public class CheckingAccount : BankAccount<CheckingAccount>
{
}
In order to use inheritance, you need an instance of an object and a member of that object. In this case, for the object we can't use BankAccount/SavingsAccount because then we would already have what we're trying to get. This means we need an actual factory object, which is what most people are talking about when they talk about a factory. So if we pull that out into a Factory and use inheritance...
public class BankAccountFactory { public virtual GetAccount() { return new BankAccount(); } }
public class SavingsAccountFactory : BankAccountFactory { public override GetAccount() { return new SavingsAccount(); } }
But now how do we get an instance of the proper type? We've just pushed our problem one layer deeper.
Instead, what you probably want to do, is use some sort of configuration to determine the type, or pass the type you want into a method.
public BankAccount GetAccount(AccountType type) { /* */ }
or
public BankAccount GetAccount() { /* Access config */ }
For a simple answer to your question: You don't need to use generics or anything like that, you just need your method to not be static...

MVC generic repository common dataColumn

I have a generic repository that I use for common things such as FetchAllData, GetbyID and so on... Anyway, I want to include a Deactivate(T Entity) method so that instead of deleting data I will just turn their status off so the user will not see the data, but I can see it whenever I need. Basically, something similar to:
public interface IGenericRepository<T> where T : class {
...somecode
}
public class GenericRepository<T> : IGenericRepository<T> where T : class {
public T GetbyID(int id) { ... }
public void Deactivate(T entity) {
entity.stat = 0; // I know that this stat is common in all tables. However,
// my problem is that I don't know how to make appear stat
// in IntelliSense.
}
}
I know that this can be done, but I how do I do it?
Declare a interface:
public interface IDeactivatable {
int stats { get; set; }
}
Then your entities must derive from IDeactivatable.
Tip: You can add a generic type constraint too:
[...] IGenericRepository<T> where T : class, IDeactivatable [...]

Categories

Resources