Bind Two Generic Type - c#

I have two parallel class hierarchy, where the first hierarchy is for an API while the second is used in the model layer.
The same type has one representation(class) in each hierarchy and I want to 'bind' (more later) this two classes in order to use generics.
API
/ \
ApiA ApiB
Model
/ \
ModelA ModelB
For instance, once this function
public string DoSomething<APIType> (APIType value) {
gets an APIType as argument (e.g. ApiB), I want to call the associated generic method that takes a ModelType as type argument (ModelB in this case).
I tried something similar to this:
public string DoSomething (ApiType value) where ModelType: Model where ApiType : API
But I then discover that C# can't do partial inference, so this:
class ApiB : Api<ModelB> {}
ApiB obj;
DoSomething(obj)
can't work (both type arguments are required)
I tried to implement something similar to C++ traits but it did not work.
It would be possible to use only Type, but I am doing this in order to get the additional compiler checking.
I guess this is not a big problem, however I would like to know if someone knows a solution.

It's very complex question. Check this code, I've replaced associated generic method call with generic constructor of List. Coment if there is difference between what you questioned and what I understood from question.
class Program
{
public class Model { }
public class ModelB : Model { }
public class Api<T> where T : Model
{
public List<T> CallGenericMethod()
{
return new List<T>();
}
}
public class ApiB: Api<ModelB> { }
public static string DoSomething<T>(Api<T> a) where T : Model
{
var b = a.CallGenericMethod();
return b.GetType().ToString();
}
static void Main(string[] args)
{
ApiB a = new ApiB();
Console.WriteLine(DoSomething(a));
}
}
Edit two types generic version
public class Api<TApi, TModel> where TApi: Api<TApi, TModel> where TModel : Model
{
public List<TModel> CallGenericMethod()
{
return new List<TModel>();
}
}
public class ApiB: Api<ApiB, ModelB> { }
public static string DoSomething<TApi, TModel>(Api<TApi, TModel> a) where TApi : Api<TApi, TModel> where TModel: Model
{
return new Dictionary<TApi, TModel>().GetType().ToString();
}

Related

"Hiding" generic methods with nongeneric method in child class

I have written some code and I'm curious as to whether or not there is a danger in what I'm doing that I'm unaware of.
I have tried searching and most of the questions I found dealt with how to make things generic which isn't my issue. I also looked in the C# spec for .net 4.5 under section 13.4.3 - Generic Methods and 7.5.2 in regards to Type inference and finally 7.5.2.12 Inferred return type and they don't really cover what I'm trying to do.
Basically I have a hierarchy of classes
public class SomeBaseClass { }
public class SomeClass : SomeBaseClass { }
public class AnotherClass : SomeBaseClass { }
public class BaseData
{
public SomeBaseClass mMember;
public BaseData() { }
public TType GetMember<TType>()
where TType : SomeBaseClass
{
return (TType)mMember;
}
}
public class Data : BaseData
{
public Data()
{
mMember = new SomeClass();
}
//Is this bad
public SomeClass GetMember()
{
return base.GetMember<SomeClass>();
}
}
The compiler doesn't complain because I'm not hiding the base class method. This is shown that intellisense lists them as two separate methods. I've written several tests which all behave the way I would expect them to and when looking at things like List<> there are instances of methods that have both a generic and nongeneric implementation (for example AsParallel from ParallelEnumerable) but the difference is that in this case both methods exist in the same class and take in a generic and nongeneric parameter respectively.
The tests I ran and showed work the way I would expect are listed below.
class Program
{
static void Main(string[] args)
{
BaseData lData = new Data();
Data lData2 = new Data();
//Call base method with type
SomeBaseClass lTest = lData.GetMember<SomeClass>();
//Cast and call derived method
SomeClass lTest2 = ((Data)lData).GetMember();
//Call base method with type and then cast
SomeClass lTest3 = (SomeClass)lData.GetMember<SomeBaseClass>();
//Call derived method directly
SomeClass lTest4 = lData2.GetMember();
//Throw InvalidCastException
SomeBaseClass lTest5 = lData2.GetMember<AnotherClass>();
}
}
The main reason for this is that I would like that any caller code doesn't have to know the generic type when the class itself already has this information. It's to avoid having to write
lData.GetMemberType<...>();
all over the place.
I apologize if this question is too broad or opinionated. Mostly I'm just wondering if there is anything in this scenario that wouldn't work the way I would think or have a hidden bug etc.
Your question is a little too vague to give a very good answer (what are you using this for? what is the purpose of this design?).
I don't think the name overlap is all that problematic, but it does seem like a symptom of a problematic design and a misuse of generics (all that casting should clue you in on that).
Ideally, your class itself should be generic, and you should use the generic type parameter throughout. That will save you from all the casting you are doing:
public class SomeBaseClass { }
public class SomeClass : SomeBaseClass { }
public class AnotherClass : SomeBaseClass { }
public class BaseData<TType> where TType : SomeBaseClass
{
protected TType mMember;
public BaseData() { }
public BaseData(TType member)
: this()
{
mMember = member;
}
public TType GetMember()
{
return mMember;
}
}
public class Data : BaseData<SomeClass>
{
public Data()
: base(new SomeClass())
{
}
// no need to implement GetMember(); base class has it covered
}

Returning child type in Parent class

public abstract class Base
{
public Base ClassReturn()
{
return this;
}
}
Is there possibility to return child type that invoked ClassReturn method?
I've done that in extension method:
public static T ClassReturn<T>(this T obj) where T : Base
{
return (T) obj.ClassReturn();
}
But I want to embeed it in Base class instead of extension method. Is there possibility to do that with generics?
I will copy my comment which describes what I want to achieve:
I need something similiar to builder pattern and I have different
classes that depending on previous operations do something else, now I
want to have a similiar functionality in every of them and when I use
it I lose object type. So my solution is either implement that
functionality multiple times in every class or create extension
method. But I always thought when it is possible to make extension
method for class then I can embeed that in class, but as I see it is
not possible.
Full example:
public class Child1 : Base
{
public Child1 Operation1()
{
Console.WriteLine("operation1");
return this;
}
}
public class Child2 : Base
{
public Child2 Operation2()
{
Console.WriteLine("operation2");
return this;
}
}
static void Main(string[] args)
{
Child1 ch = new Child1();
ch.Operation1().Operation1().ClassReturn().Operation1()
}
I can't use Operation1 after ClassReturn if I don't use extension method.
Try this one:
public abstract class Base<T> where T: Base<T>
{
public T ClassReturn
{
get { return (T)this; }
}
}
public class Child1 : Base<Child1>
{
}
public class Child2 : Base<Child2>
{
}
From your question and your comments, what you are trying to achieve is not possible directly from the type system. By returning an instance of Base you are specifically saying that all you are interested is that you have something that derives from Base, but that the specific class doesn't matter. Statically, the compiler no longer has the information it needs to perform a cast.
If you are trying to get the original type back statically, then you have to supply the information to the compiler, and in this case you can't guarantee that you have the correct information. In the example below, the instance is created from derived type A but attempted to be cast to derived type B through the extension, the compiler will allow the code to compile, but you'll get an exception at runtime.
public class A : Base { }
public class B : Base { }
public static class BaseExtensions
{
public static T GetAsT<T>(this Base base) where T: Base
{
return (T)base;
}
}
public static void Main()
{
Base obj = new A();
B b = obj.BaseAsT<B>(); // This compiles but causes an exception
}
You should look up the Liscov Substitution Principle to get information on how to properly work with base and derived classes in the system as a whole, and then write up a question dealing specifically with the result you are trying to achieve.

Force a child class to pass itself as the Generic parameter to the base class

I want to force my child classes to pass themselves as as the generic parameter to the parent class.
For example :
class BaseClass<T> where T: BaseClass
{
//FullClassName : Tuple [Save,Update,Delete]
Dictionary<string,Tuple<delegate,delegate,delegate>> dict = new Dictionary...;
static BaseClass()
{
RegisterType();
}
private static void RegisterType()
{
Type t = typeof(T);
var props = t.GetProperties().Where(/* Read all properties with the SomeCustomAttribute */);
/* Create the delegates using expression trees and add the final tuple to the dictionary */
}
public virtual void Save()
{
delegate d = dict[t.GetType().FullName];
d.Item1(this);
}
}
class ChildClass : BaseClass<ChildClass>
{
[SomeCustomAttribute]
public int SomeID {get;set;}
[SomeCustomAttribute]
public string SomeName {get; set;}
}
public class Program
{
public static void Main(string[] args)
{
ChildClass c = new ChildClass();
c.Save();
}
}
Obviously the above code won't compile. I'll restate : I want the child class to pass itself as the generic parameter and not any other child of BaseClass.
(The above code is kind of a psuedo code and will still not compile).
You can do this:
public class BaseClass<T> where T: BaseClass<T> { }
public class ChildClass : BaseClass<ChildClass> { }
But this doesn't force you to use ChildClass as the generic parameter. You could do this public class OtherChildClass : BaseClass<ChildClass> { } which would break the "coontract" that you want to enforce.
The direct answer is that if your accessing a static method then typeof(T) will give you the type for reflection.
However, there is probably better solutions than using reflection. Options:
1) Static constructor on the child class.
2) Abstract method declared in the base class.
I do not know the application, but I get concerned about my design if I feel like using a static constructor, I also get concerned if a base class needs to initialize the child class.
I suggest looking at injection as a solution rather than inheritance. It offers superior unit testing and often a better architecture.
More info (after initial post), this is my preferred solution:
public interface IRegesterable
{
void Register();
}
public class Widget : IRegesterable
{
public void Register()
{
// do stuff
}
}
public class Class1
{
public Class1(IRegesterable widget)
{
widget.Register();
}
}
Hope this helps
The ConcurrentDictionary is being used as a Set<Type>. We can check in the Set<Type> if the type has been initialized. If not we run RegisterType on the type.
public abstract class BaseClass
{
//Concurrent Set does not exist.
private static ConcurrentDictionary<Type, bool> _registeredTypes
= new ConcurrentDictionary<Type, bool>();
protected BaseClass()
{
_registeredTypes.GetOrAdd(GetType(), RegisterType);
}
private static bool RegisterType(Type type)
{
//some code that will perform one time processing using reflections
//dummy return value
return true;
}
}
public class ChildClass : BaseClass
{
}
There are several inefficiencies with this pattern though.
object.GetType() is pretty darn slow, and inefficient.
Even with the HashSet behavior, we are checking for initialization on each instanciation. Its as fast as I can get it, but its still pretty superfluous.

Generic class with non-generic method constraint?

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>();

Specify generic type as argument param without knowing T

I'm approaching a problem while still having some ignorance regarding Generics and their proper declarations / uses. I get the premiss, but some of the ins-n-outs of generics still elude me.
Given the following code (does not compile and contains code-smell):
public interface IUIConcern<out T> where T : IUIConcernExtension
{
string Name { get; }
Func<T> Extend();
}
public class UIConcern
{
public static void Register<T>(string concernName, IUIConcern<T> uiConcern) where T : IUIConcernExtension
{
Concerns.Add(uiConcern);
}
public static List<IUIConcern<T>> Concerns{
get {
// Logic...
}
set {
// Logic...
}
}
}
... I have a few questions:
Why do I have to specify this part public static void Register<T>(string concernName, IUIConcern<T> uiConcern) where T : IUIConcernExtension
with a constraint when I have already constrained the T in the declaration public interface IUIConcern<out T> where T : IUIConcernExtension
How can I have a property that holds a List<> of my IUIConcern<T> without knowing T other than knowing it will be derived from IUIConcernExtension?
Again, I realize this doesn't compile and is not correct, just looking to see how I can hold a list of generic items that may have many different type of IUIConcern<> elements.
Thank you!
You need to have a base interface, for instance:
public interface IUIConcern
{
string Name { get; }
}
public interface IUIConcern<out T> : IUIConcern where T : IUIConcernExtension
{
Func<T> Extern();
}
How you would define Concerns and Register would depend on how you treat T. Alternatively if you only deal with instances where you know T, you could use a Dictionary<Type, List<IUIConcern>> to hold anything, or potentially drop the base interface and just store using object depending on what you need in your controller code.
The problem is not located at the interface, but the problem is because of your generic implementation using static methods and properties.
The answer from Guvante was correct when saying that you need to define the IUIConcernExtension, but that is of course very logical, so im assuming you have just omitted that part since it does not matter for the issue you are facing.
The problem in the code is that you have created a class that has static methods and procedures, with the generic definition not laying at class level, but at methods level, because of this, the property that has and the Method cannot assume you are always with the same type!!
Lets say you call call :
Register<string>("something", UIConcern<string>)
but before that you have already called:
Register<Type>("something", UIConcern<Type>)
How could the compiler allows you to that?! So the answer is to define the generic type at class level, with this all properties and methods will be of same .
Also you need to use a private member for your list, since you doing everything static, the correct code should be:
interface IUIConcernExtension
{
string Name { get; }
}
public interface IUIConcern<out T> where T : IUIConcernExtension
{
Func<T> Extend();
}
public class UIConcern<T> where T : IUIConcernExtension
{
private static List<IUIConcern<T>> _Concerns = new List<IUIConcern<T>>();
public static void Register(string concernName, IUIConcern<T> uiConcern)
{
Concerns.Add(uiConcern);
}
public static List<IUIConcern<T>> Concerns
{
get { return _Concerns; }
set { _Concerns = value; }
}
}

Categories

Resources