I have a generic class that all my DAO classes derive from, which is defined below. I also have a base class for all my entities, but that is not generic.
The method GetIdOrSave is going to be a different type than how I defined SabaAbstractDAO, as I am trying to get the primary key to fulfill the foreign key relationships, so this function goes out to either get the primary key or save the entity and then get the primary key.
The last code snippet has a solution on how it will work if I get rid of the generic part, so I think this can be solved by using variance, but I can't figure out how to write an interface that will compile.
public abstract class SabaAbstractDAO<T> :ISabaDAO<T> where T:BaseModel
{
...
public K GetIdOrSave<K>(K item, Lazy<ISabaDAO<BaseModel>> lazyitemdao)
where K : BaseModel
{
...
}
I am getting this error, when I try to compile:
Argument 2: cannot convert from 'System.Lazy<ORNL.HRD.LMS.Dao.SabaCourseDAO>' to 'System.Lazy<ORNL.HRD.LMS.Dao.SabaAbstractDAO<ORNL.HRD.LMS.Models.BaseModel>>'
I am trying to call it this way:
GetIdOrSave(input.OfferingTemplate,
new Lazy<ISabaDAO<BaseModel>>(
() =>
{
return (ISabaDAO<BaseModel>)new SabaCourseDAO() { Dao = Dao };
})
);
If I change the definition to this, it works.
public K GetIdOrSave<K>(K item, Lazy<SabaCourseDAO> lazyitemdao) where K : BaseModel
{
So, how can I get this to compile using variance (if needed) and generics, so I can have a very general method that will only work with BaseModel and AbstractDAO<BaseModel>? I expect I should only need to make the change in the method and perhaps abstract class definition, the usage should be fine.
UPDATE:
With a very helpful response I have a slightly improved example, but an interesting dilemna:
I have this defined now, and I don't have any in or out on T here because I get errors that contradict, if out T then I get that it must be contravariantly valid and if in T then covariantly valid, so I made it invariant, since it appears VS2010 can't figure it out.
public interface ISabaDAO<T> where T:BaseModel
{
string retrieveID(T input);
T SaveData(T input);
}
I get this error, though it did compile:
System.InvalidCastException: Unable to cast object of type 'ORNL.HRD.LMS.Dao.SabaCourseDAO' to type 'ORNL.HRD.LMS.Dao.ISabaDAO`1[ORNL.HRD.LMS.Models.BaseModel]'.
I fixed two code snippets above, but it appears that variance won't work as I hoped here.
I had tried this:
public delegate K GetIdOrSave<out K>(K item, Lazy<ISabaDAO<BaseModel>> lazyitemdao)
where K : BaseModel;
but I get the same problem as with the interface, if I put out it complains, so I put in and the opposite complaint.
I think I could get this to work if this was legal:
public delegate K GetIdOrSave<K>(in K item, out Lazy<ISabaDAO<BaseModel>> lazyitemdao)
where K : BaseModel;
C# 4.0 support for covariance and contravariance when working with delegates and interfaces.
How is Generic Covariance & Contra-variance Implemented in C# 4.0?
So if you can use the generic delegate Lazy with a Interface as parameter so try somthing like this:
//covariance then you can save Giraffe as SicilianGiraffe but you cannot save Giraffe as Animal; contr-variance realization is not imposible in your case(just theoreticaly)
public interface ISabaDAO<out T> where T: BaseModel{
int retrieveID(BaseModel);
T SaveData(BaseModel);
}
public abstract class SabaAbstractDAO<T> : ISabaDAO<T>{
...
// in this case Lazy should be covariance delegate too
// delegate T Lazy<out T>();
public K GetIdOrSave<K>(K item, Lazy<ISabaDAO<BaseModel>> lazyitemdao) where K : BaseModel
{
...
return (K)itemdao.SaveData(item);// is not safe
...
}
}
public class Course : BaseModel{}
public class SabaCourseDAO : SabaAbstractDAO<Course>{}
//so you can cast SabaCourseDAO to ISabaDAO<Course> and ISabaDAO<Course> to ISabaDAO<BaseModel>
// then next invoking should be valid
GetIdOrSave(new Course (), new Lazy<ISabaDAO<Course>>(() =>
{
return new SabaCourseDAO() { Dao = Dao };
})
Cannot check it. I have not got VS2010.
Related
class Base, and class Ext extends Base.
class B<T> with typed method foo<T>(value:T)
Why B<Base>.foo doest not accept instance of B<Ext> (implicit downcast of the type parameter?) by default?
Here is an example
http://try.haxe.org/#d443f
class Test {
static function main() {
var bExt = new B(new Ext());
var bBase = new B(new Base());
bBase.foo(bExt);
//ofc
//bBase.foo(cast bExt);
}
}
class B<T>
{
public function new(v:T)
{
}
public function foo(v:B<T>)
{
//
}
}
class Base {
public function new(){}
}
class Ext extends Base {
public function new(){
super();
}
}
Is there any way to trigger implicit cast of the type parameter for B.foo?
There are three ways to interpret and answer your question:
1. foo(v:B<T>):
This is your example and it doesn't compile because T isn't allowed to be be variant. It happens because of the very existence of foo and because allowing bBase.foo(bExt), that is, unifying bExt with bBase, will then allow bBaseOfbExt.foo(bBase).
It is the fact that foo exists and that it can potentially modify the type that makes the bExt unification with bBase unsafe; you can see a similar (but maybe clearer) explanation in the manual, using arrays: type system – variance.
2. foo(v:T):
This is closer to what's on the body of your question (but not in the example) and it works fine.
3. foo<A>(v:B<A>):
Finally, if you have a type parameterized method, it also works, but you'd probably face other variance issues elsewhere.
I've created my project in vs2008.It works fine.But when i opened the solution and try to build it in vs2012 i am getting the following error in TransactionDB.dbml page.
a partial method may not have multiple defining declarations
What could be the problem??
.net supports partial methods.
It means you write a definition in one part of the partial class and the implementation in another. Like this:
partial class MyClass
{
partial void MyPartialMethod(string s);
}
// This part can be in a separate file.
partial class MyClass
{
// Comment out this method and the program will still compile.
partial void MyPartialMethod(string s)
{
Console.WriteLine("Something happened: {0}", s);
}
}
In your case I you have the two definitions of the partial method causing the compiler to fail.
Source MSDN
The defining declaration of a partial method is the part that specifies the method signature, but not the implementation (method body). A partial method must have exactly one defining declaration for each unique signature. Each overloaded version of a partial method must have its own defining declaration.
To correct this error
Remove all except one defining declaration for the partial method.
Example
// cs0756.cs
using System;
public partial class C
{
partial void Part();
partial void Part(); // CS0756
public static int Main()
{
return 1;
}
}
I got a class
public class ID_Name<T>
{
public ID_Name(T id)
{
this.ID = id;
}
public T ID { get; set; }
public string Name
{
get
{
return Helper.SomeReturnValue;
}
}
}
All I want to do is generate a custom List of ID_Name where I can pass an ID_Name.ID as parameter in Add.
I tried the following:
public class ID_Name_List<T> : IList<T> where T : ID_Name<T>
but then I get the following error:
The type "EProtokollStatus" cannot be used as type parameter "T" in
the generic type or method "ID_Name_List<\T>". There is no boxing
conversion or type parameter conversion from "EProtokollStatus" in
ID_Name<\EProtokollStatus>.
I read something about this issue here: No boxing or type parameter conversion for generic Type parameter but I can't see a restriction except ID_Name here.
This may be wrong somehow, because everything I want to express is "use the same type T as in ID_Name for ID_Name_List", but how do I achieve that?
I found something here: C#: Declaring and using a list of generic classes with different types, how? but I don't want to create many different classes for all possible types.
All I want to achieve is something like
ID_Name_List<EProtokollStatus> myList = new ID_Name_List<EProtokollStatus>();
myList.Add(EProtokollStatus.ValueX);
Your current constraint makes no sense. Did you mean:
public class ID_Name_List<T> : IList<ID_Name<T>>
Suppose I have a List<IMyInterface>...
I have three classes which implement IMyInterface: MyClass1, MyClass2, and MyClass3
I have a readonly Dictionary:
private static readonly Dictionary<Type, Type> DeclarationTypes = new Dictionary<Type, Type>
{
{ typeof(MyClass1), typeof(FunnyClass1) },
{ typeof(MyClass2), typeof(FunnyClass2) },
{ typeof(MyClass3), typeof(FunnyClass3) },
};
I have another interface, IFunnyInteface<T> where T : IMyInterface
I have a method:
public static IFunnyInterface<T> ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
IFunnyInterface<T> otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
I'm trying to call the constructor of FunnyClasses and insert as parameter my MyClass object. I don't want to know which object it is: I just want to instantiate some FunnyClass with MyClass as a parameter.
What happens when I call ConvertToFunnyClass, T is of type IMyInterface, and when I try to cast it to FunnyInterface<T>, it says I can't convert FunnyClass1, for instance, to FunnyInterface<IMyInterface>
My current workaround (not a beautiful one), is this:
public static dynamic ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
var otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
And I don't like it because the return type is dynamic, so when I access it from somewhere else, I have no idea what type it is, and I lose intellisense, and stuff. I don't know about any performance implications either.
Any clues?
Thanks in Advance!
Resolution
As I'm using C# 4.0, I could stop casting errors using covariance (output positions only), and so I changed my IFunnyInterface to
IFunnyInteface<out T> where T : IMyInterface
Thank you all for the replies.
Essentially, your problem is that you are trying to convert FunnyInterface<T> to FunnyInterface<IMyInterface>. As has been mentioned several times (one example is here, more information here), this is not valid in most circumstances. Only in .NET 4, when the generic type is an interface or delegate, and the type parameter has been explicitly declared as variant with in or out, can you perform this conversion.
Is FunnyInterface actually an interface?
thecoop answer points you exactly to why you can't do it.
A cleaner solution to the problem (besides using dynamic) would be a base non-Generics Interface:
public interface IFunnyInterfaceBase
{
}
public interface IFunnyInteface<T> : IFunnyInterfaceBase
where T : IMyInterface
{
}
And you need to move methods signature you use in that code from IFunnyInteface to IFunnyInterfaceBase.
This way you would be able to write something like this:
MyClass2 c2 = new MyClass2();
IFunnyInterfaceBase funnyInstance = c2.ConvertToFunnyClass();
The Exception you said you got in your code is not due to the extension method signature itself (the method is fine)..it is originated by the type of your lvalue (the type of the variable you use to store its return value)!
Obviously this solution applies only if you can modify IFunnyInterface source code!
I'd like make possible a generic method overload.
Since I need to create an ObjectSet<..> without knowing the generic type contained in, I wold build something like this:
public IQueryable<T> MyMethod<T>() where T : class, (IMyFirst || IMySecond) //notice the syntax..!
{
if(typeOf(T) is IMyFirst..
else ...
}
How can I reach my purpose..?
Update:
#BrokenGlass wrote:
This type of constraint is not possible in C# - you could however constrain to IFoo and have IMyFirst and IMySecond both implement IFoo.
But that suggestion is not applicable, please see this:
interface1 { property1 {..}}
interface2 { property2 {..}}
interfaceIFoo : interface1, interface2 { }
by any method:
MyWrapper.Retrieve<EntityProduct>(myObjContext); //error-> EntityProduct implements interface1 only!!
by other any method:
MyWrapper.Retrieve<EntityOrder>(myObjContext); //error-> EntityOrder implements interface2 only!!
and here:
public static IQueryable<T> Retrieve<T>(ObjectContext context) where T :class, interfaceIFoo
{
var query = context.CreateObjectSet<T>().AsQueryable();
//...
This type of constraint is not possible in C# - you could however constrain to IFoo and have IMyFirst and IMySecond both implement IFoo.
If you can live with dependencies on Entity Framework you could alternatively also use EntityObject
A disjunctive generic constraint doesn't really make sense. Those constraints provide compile-time information to the method, so there's not much point in constraints that result in an ambiguous type at compile time. For instance, if your method is just going to resort to run-time type checking, you might as well just do this:
public IQueryable<T> MyMethod<T>() where T : class
{
if (typeOf(T) is IMyFirst) ...
else ...
}
If you feel you need the type checking on input and a pseudo-abstraction, perhaps extension methods that happen to be identically named would suffice:
public static IQueryable<IMyFirst> MyMethod(this IMyFirst input)
{
return ...
}
public static IQueryable<IMySecond> MyMethod(this IMySecond input)
{
return ...
}