Generic method call cannot convert from class name to full class name - c#

I have an interface as follows:
public interface ISelectEntity
{
List<T> GetFromDB<T, O>(O data);
}
I'm implementing it as follows within a StatusCodes class
List<StatusCodes> ISelectEntity.GetFromDB<StatusCodes, StatusCodesInputParameters>(StatusCodesInputParameters data)
{
return EntitiesClass.PopulateStatusCodes(EntitiesDAL.GetStatusCodes(data));
}
I'm receiving the following error, however:
Error 2 Argument '1': cannot convert from 'StatusCodesInputParameters' to 'Namespace.StatusCodesInputParameters'
Assuming that my namespace is called Namespace, that's the error I receive. All of this is within this one namespace. What am I doing wrong?

You cannot change method signatures in derived classes. You could define the generic argument on the interface though instead of doing it on the method:
public interface ISelectEntity<T, O>
{
List<T> GetFromDB(O data);
}
and a sample explicit implementation might look like this:
public class Foo : ISelectEntity<StatusCodes, StatusCodesInputParameters>
{
List<StatusCodes> ISelectEntity<StatusCodes, StatusCodesInputParameters>.GetFromDB(StatusCodesInputParameters data)
{
return EntitiesClass.PopulateStatusCodes(EntitiesDAL.GetStatusCodes(data));
}
}
and a sample implicit implementation:
public class Foo : ISelectEntity<StatusCodes, StatusCodesInputParameters>
{
public List<StatusCodes> GetFromDB(StatusCodesInputParameters data)
{
return EntitiesClass.PopulateStatusCodes(EntitiesDAL.GetStatusCodes(data));
}
}

Related

Return generic interface implementation with different generic type

I have created this simple generic interface:
public interface IInitializerSettings<in ViewerType> where ViewerType : Component
{
void Apply(ViewerType dataViewer);
}
And added an implementation for it:
public class MenuSettings : IInitializerSettings<CustomGridLayout>
{
public void Apply(CustomGridLayout dataViewer)
{
Debug.Log("Applied");
}
}
public class CustomGridLayout : CustomLayout
{
// The implementation code
}
Now I try to use it like that:
public IInitializerSettings<CustomLayout> GetDefaultSettings()
{
return new MenuSettings();
}
But I get this error "Cannot convert type MenuSettings to return type IInitializerSettings"
I don't understand why it isn't allowed, CustomGridLayout inherits CustomLayout.
All I could find is this question, but this solution doesn't work for me (I can't use the out keyword).
The reason you cannot do this is because for a contravariant interface (specified by your use of in for the generic type parameter) you cannot implicitly convert it to an instance of a less derived type. I think the bullet points in the docs explains it fairly ok, if you think in terms of IEnumerable<T> (covariant) and Action<T> (contravariant).
As Selvin mentions in the comments the Apply method in MenuSettings expects an instance of CustomGridLayout, so trying to cast MenuSettings to IInitializerSettings<CustomLayout> is not possible because public void Apply(CustomGridLayout dataViewer) cannot handle a CustomLayout as input. Let me give an example:
public class CustomLayout
{
public void SetupCustomLayout() { ... }
}
public class CustomGridLayout : CustomLayout
{
public void SetupGrid() { ... }
}
public class MenuSettings : IInitializerSettings<CustomGridLayout>
{
public void Apply(CustomGridLayout dataViewer)
{
dataViewer.SetupGrid();
}
}
// Later in the code...
var menuSettings = new MenuSettings();
// This cast is what GetDefaultSettings() is trying to do
var genericSettings = (IInitializerSettings<CustomLayout>)menuSettings;
var layout = new CustomLayout();
// Looking at the type of 'genericSettings' this following line should be possible
// but 'MenuSettings.Apply()' is calling 'dataViewer.SetupGrid()' which doesn't exist
// in 'layout', so 'layout' is not a valid input
genericSettings.Apply(layout);
So in relation to the docs you have defined IInitializerSettings<ViewerType> as a contravariant interface, but are trying to use it as a covariant interface - which is not possible.

The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'QueryAPI.Query<T>()

I'm writing some code that should update some fields with a common logic on different remote objects. Therefore I use given API. The Test Class is my own implementation. The other two classes are given by the API.
When I write the following code i get the error
The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'QueryAPI.Query<T>()
Code:
public class Test<T> where T : class, UnicontaBaseEntity
{
private async Task Foo<T>(QueryAPI queryAPI, CrudAPI crudAPI, SyncSettings syncSettings)
{
Task<T[]> result = await queryAPI.Query<T>();
}
}
public interface UnicontaBaseEntity : UnicontaStreamableEntity
{
int CompanyId { get; }
Type BaseEntityType();
}
public class QueryAPI : BaseAPI
{
...
public Task<T[]> Query<T>() where T : class, UnicontaBaseEntity, new();
...
}
Any ideas on this?
Thanks in advance.
KR
Mike
I would remove T from Foo() here since your parent class Test<T> is already generic.
You should also add a new() constraint otherwise there will be another error since QueryAPI expects a type with default constructor.
Also, some renames to include Async are in order.
public class Test<T> where T : class, UnicontaBaseEntity, new()
{
private async Task FooAsync(QueryAPI queryAPI, CrudAPI crudAPI, SyncSettings syncSettings)
{
Task<T[]> result = await queryAPI.QueryAsync<T>();
}
}
public interface UnicontaBaseEntity : UnicontaStreamableEntity
{
int CompanyId { get; }
Type BaseEntityType();
}
public class QueryAPI : BaseAPI
{
...
public Task<T[]> QueryAsync<T>() where T : class, UnicontaBaseEntity, new()
...
}

C# generic Interface implementation to derived class

I am stuck in implementation of generic class and interface. I am not sure what i wanted to do is possible or not.
here is my code:-
I have defined a generic class whose type not define like
public class Response<T>
{
public T Data { get; set; }
public Response()
{
Data = default(T);
}
}
and a Interface which right now have one function
public interface IOInterface<T> where T : Response<T>
{
Response<T> ReadAdvantechChannel(Dictionary<string, string> IOParameters);
}
And one derive class who will implements this interface :-
public class AdvantechOperation : IOInterface<T>
{
public Response<AIRecordInfo> ReadAdvantechChannel(Dictionary<string, string> IOParameters)
{
Response<AIRecordInfo> resp = new Response<AIRecordInfo>();
}
}
and AIrecordinfo is again class
public class AIRecordInfo
{
double[] ArryMaxValueAIdouble;
double[] ArryMinValueAIdouble;
double[] ArryAVGValueAIdouble;
}
what i want to do that implement a class who implement define interface but return type of interface function is not clear for my future derived class thats why i have made it generic and try to implement it my present class "AdvantechOperation". My interface will have three functions and all function return type will different to each other thats why i made it generic return type Response and in my present class AdvantechOperation, T replaced by AIRecordInfo.
But I am facing below Error while compiling this project
Error 7 The type 'T' cannot be used as type parameter 'T' in the
generic type or method 'IOModule.IOInterface'. There is no boxing
conversion or type parameter conversion from 'T' to
'IOModule.Response'. D:\MTS\SMS\DAQAdvantechdll\DAQAdvantechdll\IOCommunication.cs 28 18 IOModule
Error 8 'IOModule.AdvantechOperation' does not implement interface
member
'IOModule.IOInterface.ReadAdvantechChannel(System.Collections.Generic.Dictionary)'.
'IOModule.AdvantechOperation.ReadAdvantechChannel(System.Collections.Generic.Dictionary)'
cannot implement
'IOModule.IOInterface.ReadAdvantechChannel(System.Collections.Generic.Dictionary)'
because it does not have the matching return type of
'IOModule.Response'. D:\MTS\SMS\DAQAdvantechdll\DAQAdvantechdll\IOCommunication.cs 28 18 IOModule
Get rid of the generic type constraint for your interface and use AIRecordInfo as the generic type argument when implementing the interface:
public class AdvantechOperation : IOInterface<AIRecordInfo>
{ ... }
It seems to me that you want this:
public class Response<T> { }
public interface IOInterface<T> where T : Response<T>
{
T ReadAdvantechChannel(Dictionary<string, string> IOParameters);
}
public class AdvantechOperation : IOInterface<AIRecordInfo>
{
public AIRecordInfo ReadAdvantechChannel(Dictionary<string, string> IOParameters)
{
return new AIRecordInfo();
}
}
public class AIRecordInfo : Response<AIRecordInfo>
{
double[] ArryMaxValueAIdouble;
double[] ArryMinValueAIdouble;
double[] ArryAVGValueAIdouble;
}
Response<T> no longer needs a body because IOInterface<T>'s method simply returns T which must inherit from Response<T>.

Factory class returning a generic interface

I have few concrete which uses the following type of interface
interface IActivity<T>
{
bool Process(T inputInfo);
}
Concrete classes are like as follows
class ReportActivityManager :IActivity<DataTable>
{
public bool Process(DataTable inputInfo)
{
// Some coding here
}
}
class AnalyzerActivityManager :IActivity<string[]>
{
public bool Process(string[] inputInfo)
{
// Some coding here
}
}
Now how can i write the factory class which retuns a generic interface some thing like IActivity.
class Factory
{
public IActivity<T> Get(string module)
{
// ... How can i code here
}
}
Thanks
You should create generic method, otherwise compiler will not know type of T in return value. When you will have T you will be able to create activity based on type of T:
class Factory
{
public IActivity<T> GetActivity<T>()
{
Type type = typeof(T);
if (type == typeof(DataTable))
return (IActivity<T>)new ReportActivityManager();
// etc
}
}
Usage:
IActivity<DataTable> activity = factory.GetActivity<DataTable>();
Often this is implemented as in lazyberezovsky's answer. In c++ you could use template specialization to get compiler errors when you try to create a type the factory does not handle.
You can't do that in C# but you can get close. Though the code might look a little surprising which in turn could be a problem.
public static class Factory {
public static IActivity<someType> Get(this someType self){
//stuff specific to someType
}
public static IActivity<someOtherType> Get(someOtherType self){
//stuff specific to someOtherType
}
public static T Creator<T>(){
return null;
}
}
The usage would then be
IActivity<someType> act = Factory.Creator<someType>().Get();
of course this only works if you can pass a concrete type. If you need to pass a type parameter things get more complicated.

Accessing Implemented Interface Methods in other classes

I'm a C# newbie and am trying to implement an interface. I know I can't put access modiefiers onto interface methods so how do I get access to 'TestValue' in the public static 'Create' method of 'TestClass2' below? the error I get is...
'TestClass1' does not contain a definition for 'TestValue' and no extension method 'TestValue' accepting a first argument of type 'TestClass1' could be found
public interface IParent
{
string TestValue { get; }
}
public class TestClass1 : IParent
{
string IParent.TestValue
{
get { return "hello"; }
}
}
public class TestClass2
{
private string _testValue;
public static TestClass2 Create(TestClass1 input)
{
TestClass2 output = new TestClass2();
output._testValue = input.TestValue;
return output;
}
}
Add the public access modifier in your concrete implementation:
public class TestClass1 : IParent
{
private TestClass1 _testValue;
public string TestValue
{
get { return "hello"; }
}
}
EDIT: as you actually wrote an explicit interface implementation, I recommend you to see the following SO question: C# Interfaces. Implicit implementation versus Explicit implementation
You don't need access modifiers in the interface declaration because the point of an interface is to define the publicly accessible contract for any class implementing the interface. Essentially, although you don't specify an access modifier in the definition, all methods/properties are taken to be public.
This means that when you implement the interface, you're contractually bound to provide a public method/property that matches the interface's method/property signature.
In a nutshell, add the public access modifier to your concrete classes implementations and you'll be sweet.
I tried converting the object into the interface to get the solution like so
public class TestClass2
{
private string _testValue;
public static TestClass2 Create(TestClass1 input)
{
TestClass2 output = new TestClass2();
output._testValue = ((ITestInterface)input).TestValue;
return output;
}
}
This works too but I prefer the simpler solution.

Categories