This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?
I can do
public class MyGenericClass : DL
//but i cannot do
public class MyGenericClass <T> : T
How would i do the second? if i cannot do that, how can i do something like
public class MyGenericClass <T>
{
T obj;
//have all MyGenericClass.XYZ call obj.XYZ
}
This is not possible, because depending on what type T is, the public interface of MyGenericClass would change.
If you have lots of different classes that all expose the same interface, you could declare MyGenericClass to expose that interface, and in the implementation of all of the functions delegate the calls to obj
The specific question, why can't you do this:
public class MyGenericClass<T> : T
And you can do this:
public class MyGenericClass<T>
{
T obj;
}
The reason is that the CLR likes to be able to compile a single version of the code for MyGenericClass that will work for any reference type specified for T.
It can do this for the second case, because it can quietly replace T with object and insert appropriate casts, roughly equivalent to:
public class MyGenericClass
{
object obj;
}
But for the inheritance version, that trick doesn't work.
Also, many useful facilities would be impossible to describe through interface constraints. When you inherit from a type, you can do a lot more than just call methods on it - you can override them as well. Consider this hypothetical example:
class MyBase
{
public virtual void MyVirtual() { }
}
class MyGenericDerived<T> : T
{
public override void MyVirtual()
{
Console.WriteLine("Overridden!");
}
}
MyBase obj = new MyGenericDerived<MyBase>();
obj.MyVirtual();
What I want to do there is something like a "mix-in", where MyGenericDerived supplies definitions for virtual functions in whatever base it is applied to. But how does the compiler know that T will have a method called MyVirtual that can be overridden? I'd need to put a constraint on T. How would I express that through interfaces? It's impossible. Using interfaces to describe constraints isn't an adequate solution once you allow inheritance from type parameters. So that's another reason why it doesn't exist in the language today.
You could do something like
public interface IXyzable { void xyz(); }
public class MyGenericClass<T> : IXyzable where T : IXyzable {
T obj;
public void xyz() {
obj.xyz();
}
}
Edit: Now I understand the question
You'll need all your possible T's to implement some interface so that you know that obj.XYZ() makes sense, then you can do
public interface Ixyz
{
void XYZ();
}
public class MyGenericClass<T> : Ixyz where T:Ixyz, new()
{
T obj;
public MyGenericClass()
{
obj = new T();
}
public void XYZ()
{
obj.XYZ();
}
}
I've made MyGenericClass implement Ixyz too since it obviously does expose the right method, but maybe that's best left out since it allows
var x = new MyGenericClass<MyGenericClass<SomeClass>>();
which is unlikely to ever be a good idea.
This is pretty much duck-typing, but you could use reflection.
When you create the generic class with a reference to the obj, use reflection to try and find a method with the right signature. As long as you store a reference to the method, performance won't be too bad.
class BaseGeneric<T>
{
private T obj;
private MethodInfo mi;
private const string MethodNameOfInterest = "Xyz";
public BaseGeneric(T theObject)
{
this.obj = theObject;
Type t = obj.GetType();
mi = t.GetMethod(MethodNameOfInterest);
}
public void Xyz()
{
mi.Invoke(obj, null);
}
}
Of course, you would need to add a lot more for error checking and such, but that is the gist of what you could do. Also, don't forget to add the System.Reflection namespace to your using clause.
The .NET type system won't allow type declarations of the form you're attempting. One reason why this is disallowed should be intuitive: how would MyGenericClass<T> act when T is a sealed class (e.g. System.String)?
If you absolutely need this functionality (and you know that the type T you'll be using isn't sealed), you can generate proxies at runtime using the classes in the Reflection.Emit namespace. It may also be possible to achieve this effect using AOP tools like PostSharp.
What about this:
class BaseClass<T>
{
public T property { get; set; }
}
class GenericClass<T> : BaseClass<T>
{
}
class Program
{
static void Main(string[] args)
{
GenericClass<int> l = new GenericClass<int>();
l.property = 10;
}
}
This achieves what you want to do?
Related
I am trying to do something with Generics in .Net 4.5 C# and honestly, I'm not sure if it is possible or what it's called. Which makes searching that much more difficult.
Anyways, best to explain with an example.
Let's say I have some interface:
public interface ISomeBase {}
and an example of its implementation
public class AnObject : ISomeBase {}
public class AnOtherObject : ISomeBase {}
Then I've got ClassA which has a few generic methods like so
public class ClassA
{
public T SomeMethod1<T>() where T : class, ISomeBase
{
//Do some stuff and return some T
return default(T);
}
public List<T> SomeMethod2<T>(Expression<Func<T,object>> someExpression ) where T : class, ISomeBase
{
//Do some stuff and return some List<T>
return new List<T>();
}
}
I want to be able to use it like this (which I easily can):
public class SomeImplementation
{
public void Test()
{
var obj = new ClassA();
var v = obj.SomeMethod1<AnObject>();
var v2 = obj.SomeMethod2<AnOtherObject>((t) => t.ToString());
}
}
But I also want to be able to use it like this (this won't work as is due to type argument required. I understand that T in ClassB is different from T in every method in Class A:
public class ClassB<T> : ClassA where T: ISomeBase
{
public T Tester()
{
//This is not possible and requires me to add a Type argument.
return SomeMethod1(); //I would like to leave out the type argument and have the compiler infer what it is
// Some of the time I want to be able to apply the same type to all methods on ClassA.
// And some of the time I want to be able to specify the type arguments on a per method basis
}
}
I want to avoid having to wrap ClassA into something like this:
public class ClassA<T> : ClassA where T : class, ISomeBase
{
public T SomeMethod1()
{
return SomeMethod1<T>();
}
public List<T> SomeMethod2(Expression<Func<T, object>> someExpression)
{
return SomeMethod2<T>(someExpression);
}
}
I've been searching and reading up on anything that I can get my hands on. But nothing seems to fit. Perhaps I'm not searching using the right terminology because, honestly, I don't know what it's called.
Any help or pointers will be very appreciated.
You're not giving the compiler enough information for it to infer the type argument it should use.
Type inference is a very complex process to go through but, In general if a method type parameter doesn't appear in the parameter list then no type inference is performed for that type parameter. You might want to read the C# spec. to understand the details of type inference.
Hopefully someone can further clarify it.
ok Im back with another question... It seems you when you assign base objects as another object , the base object is turned into that object, but still is without its properties for example.
public class MyObjectBase {
public void Begin() {
}
{
public class OneOfMyObjects : MyObjectBase {
public void Begin() {
base.Begin();
//do stuff
}
}
public class ManagmentClass {
public MyObjectBase myCurrentObject;
//called a only one when the program starts
public void Start() {
Mymethod(new OneOfMyObjects());
}
//generic method
public void Mymethod<T>(T Objectclass) where T : MyObjectBase {
myObject = Objectclass
myObject.Begin(); // compiler error, non existent in MyObjectBase
myObject.GetType().ToString() //returns "OneOfMyObjects"
}
}
Of course, the compiler can't find "Begin()" since begin doesn't originally exists in MyBaseObject.
I'm doing a conversion between a custom language similar to Ruby to C#(above), but this Ruby-like language doesn't come across this "problem" I'm having. It seems to compile it. Is there something in .NET4 that can solve this issues that I'm forgetting?
Well, you could just use dynamic typing:
dynamic myObject;
... but your Mymethod method can't really accept any instance of a MyObjectBase... it must have a Begin method, for example. Using dynamic typing, you'll only discover when that's not the case at execution time.
Rather than directly porting some code written for a different language with different idioms, you should think about the higher level goal that code is trying to achieve, and the most idiomatic way of achieving the same goal in C#. We can't guide you on that without more information.
Give this a whirl. The issue is that you're using a base class that doesn't provide a definition of Begin(and you knew that, just reiterating). So, the thing to do is to provide a way for the base class to have a Begin() method. In the below example, MyObjectBase is an abstract class and Begin() is an abstract method. This means that MyObjectBase will never have a definition for Begin(), but it forces all derived classes to provide a definition for Begin(). So, for example:
MyObjectBase obj1 = new MyObjectBase();
obj1.Begin(); //Won't Compile
OneOfMyObjects obj2 = new OneOfMyObjects();
obj2.Begin(); //Compiles if and only if OneOfMyObjects
//class has a definition for Begin().
Also, I'm usually programming in C++ so this may not be 100% best-practice for C#, but it's compile-able. I also changed the scope of Begin. Protected is used when you want a derived class to access something in a base class, but it isn't necessarily the scope you use when dealing with something that's derived. Begin is being accessed from outside of the base and derived classes so it needs to be public.
public abstract class MyObjectBase
{
public abstract void Begin();
}
public class OneOfMyObjects : MyObjectBase
{
public override void Begin()
{
//do stuff
}
}
public class ManagmentClass
{
public MyObjectBase myCurrentObject;
//called a only one when the program starts
public void Start()
{
Mymethod(new OneOfMyObjects());
}
//generic method
public void Mymethod<T>(T Objectclass) where T : MyObjectBase {
MyObjectBase myObject = Objectclass;
myObject.Begin(); // Shouldn't throw an error any more
myObject.GetType().ToString(); //returns "OneOfMyObjects"
}
}
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.
class test <T> where T : class
{
public void Write<T>()
{
Console.Write(typeof(T).FullName);
}
}
In the above class, it is possible to pass in a string for the class (test<string> Test = new test<string>) and then int for the method? If so, what is the output? If not, what problems does this cause? I haven't actually tried this, despite using generics (in my own classes) and generic collections, frequently.
The way I write/see generic classes is as follows:
class <T> where T : class
{
public T Write()
{
Console.Write(T.ToString());
}
}
As it was originally written no you cannot. In order to use different types at different points in the class, you must have multiple generic parameters. It is possible to define a different one at the method level and get your sample to work
class Test<T> where T : class {
public void Write<U>(U arg1) {
Console.WriteLine(arg1.ToString());
}
}
Usage
var t = new Test<string>();
t.Write(42);
As Scott pointed out you can use the same named parameter. Although doing so will cause a warning and generally speaking confuse people. It is much cleaner to have distinct names for all generic parameters currently in scope.
You'll be wanting to declare a type variable in the method separately to the class -
class Test<T> where T : class {
public void Method<U>(U val) {
Console.WriteLine(typeof(U).FullName);
}
}
I've made a test case to illustrate the problem I've run into.
The first assert passes, but the second and third both fail.
Is there a way to check either of the two failing conditions k in a different way that will work? It would be OK if it's not terribly fast as I intend to cache the results on a per-type basis.
public interface IParentInterface
{
}
public interface IChildInterface : IParentInterface
{
}
public class ParentClass<T> where T: IParentInterface
{
}
public class ChildClass : ParentClass<IChildInterface>
{
}
public class TestClass
{
public ChildClass Property { get; set; }
}
[TestFixture]
public class ScratchPad
{
[Test]
public void Assignabl()
{
var tc = new TestClass();
var tct = tc.GetType();
var pi = tct.GetProperty("Property");
Assert.IsNotNull(pi);
Assert.IsTrue(typeof(ParentClass<IChildInterface>).IsAssignableFrom(pi.PropertyType));
Assert.IsTrue(typeof(ParentClass<>).IsAssignableFrom(pi.PropertyType));
Assert.IsTrue(typeof(ParentClass<IParentInterface>).IsAssignableFrom(pi.PropertyType));
}
}
It is by design that your second assertion fails. When you write
public class ParentClass<ParentInterface>
it actually means that "ParentInterface" is now a symbol for a type argument (doing that is so confusing that, indeed, it totally confused you).
Writing
public class ChildClass : ParentClass<ChildInterface>
then sets yout type argument (yeah, the one named "ParentInterface") to the type ChildInterface. Hence, Childclass is only assignable to ParentClass<ChildInterface>.
Lastly, you should ensure that you follow conventions when definining type arguments, it will confuse you a lot less, e.g.
public class ParentClass<T>
marking interfaces with "I" will also greatly enhance understanding, e.g.
interface IParent { }
interface IChild : IParent { }
I suspect that that which you want is not possible until we get c# 4.0:
Parent<IChild>
is not assignable to
Parent<IParent>
There is currently no co/contravariance for generics.
Isn't this the covariance/contravariance thing?
Then it's just something C# currently does not support, but C# 4.0 might.
You can't, because C# 3.0 does not support variance of this kind. In C# 4.0, you should be able to.
Using another example, say you had a List<ParentInterface>, and could assign it to a List<ChildInterface>:
List<ParentInterface> parentList = List<ParentInterface>();
List<ChildInterface> childList = parentList;
The problem is that the internal storage for parentList is for ParentInterface types. If you derived another interface from ChildInterface:
public interface ParentInterface2 : ChildInterface {}
And then tried to add it to childList like so:
childList.Add(new ParentInterface2Implementation());
You would get an exception, since childList is really a List<ParentInterface> and can only store implementations of ParentInterface, which ParentInterface2 is not.