Here is my exemplary implementation of a factory producing required resources:
public abstract class Resource<T> where T : ResourceObject
{
protected string path = "base";
public IEnumerable<T> payload;
public Type resType = typeof(T);
public T GetFirst()
{
return payload.First();
}
}
public class ImageResource : Resource<Image>
{
public ImageResource () : base()
{
path = path + "/image";
}
}
public class RemoteResourcesFactory : ResourcesFactory
{
public static T Get<T>() where T : Resource<ResourceObject>, new()
{
T resource = new T();
resource.payload = load(resource.resType, resource.path); //here is some logic with instance
return resource;
}
}
And when I try to use it the error appears
Image image = RemoteResourcesFactory.Get<ImageResource>().GetFirst();
The type 'ImageResource' cannot be used as type parameter 'T' in the generic type or method 'RemoteResourcesFactory.Get<T>()'. There is no implicit reference conversion from 'ImageResource ' to 'Resource<ResourceObject>'
I am C# newbie an want to know where I failed. Or maybe it is overall architecture mistake
Related
In the code below;
CustomClass<EnType1> a = new CustomClass<EnType1>();
CustomClass<TEnum<EnType1>> b = new CustomClass<TEnum<EnType1>>();
Throws error
The type ConsoleApp2.TEnum<ConsoleApp2.EnType1> cannot be used as type parameter T in the generic type or method CustomClass<T>. There is no implicit reference conversion from ConsoleApp2.TEnum<ConsoleApp2.EnType1> to System.Enum. and The type ConsoleApp2.EnType1 cannot be used as type parameter T in the generic type or method CustomClass<T>. There is no boxing conversion from ConsoleApp2.EnType1 to ConsoleApp2.IEnum.
How do I resolve this?
Basically I want to create a generic class which I should be able to use any Enum and then any class that inherits from IEnum
Any help appreciated
Full Code:
class Program
{
static void Main(string[] args)
{
CustomClass<EnType1> a = new CustomClass<EnType1>();
CustomClass<TEnum<EnType1>> b = new CustomClass<TEnum<EnType1>>();
TEnum<EnType2> t = new TEnum<EnType2>(EnType2.B);
Console.WriteLine("Hello World!" + t.EnumValue);
}
}
In this generic class I should be able to use any Enum and then any class that inherits from IEnum
public class CustomClass<T> where T : Enum, IEnum
{
public T Enum;
}
enum EnType1
{
A = 2,
B = 3
}
enum EnType2
{
A = 0,
B = 1
}
public interface IEnum
{
public int EnumValue { get; set; }
}
public class TEnum<T> : IEnum
{
public TEnum(T enumVal)
{
EnumValue = (int)(object)enumVal;
}
public int EnumValue { get ; set ; }
}
With the OneOf you can create a custom class, which represents either a built-in enum or a custom enum.
public class EitherEnum : OneOfBase<Enum, IEnum>
{
public EitherEnum(OneOf<Enum, IEnum> _)
: base(_) { }
public bool IsStandard => IsT0;
public Enum Standard => AsT0;
public bool IsCustom => IsT1;
public IEnum Custom => AsT1;
}
You can't use OneOf<T1,T2>, because it is a struct and that can't be used as generic constraint. The same applies Language-ext's Either type.
With this little class you can do the following:
public class CustomClass<T> where T : EitherEnum
{
public T Enum;
}
CustomClass<EitherEnum> cc = new CustomClass<EitherEnum>();
cc.Enum = new EitherEnum(EnType1.A);
//OR
cc.Enum = new EitherEnum(new CustomEnum());
cc.Enum.Switch(
standard => Console.WriteLine($"Standard: {standard}"),
custom => Console.WriteLine($"Custom: {custom}"));
//OR
if(cc.Enum.IsStandard)
Console.WriteLine($"Standard: {cc.Enum.Standard}")
else if (cc.Enum.IsCustom)
Console.WriteLine($"Custom: {cc.Enum.Custom}")
I have a dynamic object Type that I assign via a constructor. Here is a simplified version of my code:
public static void Main(string[] args)
{
var x = new Shirt("Collared");
}
class Shirt {
public dynamic Type = new { };
public string ProblemVariable;
public Shirt() { }
public Shirt(string type) {
ProblemVariable = "Assigned in Constructor";
if (type == "Collared") {
Type = new Type.Collared();
}
}
class Type : Shirt {
public Type() { }
public Type(string value)
{
}
}
class Collared : Type { }
In Main(), calling x.Type.GetType() returns that my dynamic x.Type is a Type.Collared. In Type.Collared, I would like to create a function that accesses string ProblemVariable from base class Shirt:
class Collared : Type {
public void GetProblemVariable() {
Console.WriteLine(ProblemVariable);
}
}
Doing so returns a NullReferenceException. If I assign ProblemVariable as "Not modified" in my class definition:
class Shirt {
public string ProblemVariable = "Not modified";
My function GetProblemVariable returns ProblemVariable as "Not Modified".
While I am obviously able to access ProblemVariable from base class Shirt, why does Type.Collared not return ProblemVariable as "Assigned in Constructor" as defined in constructor Shirt(string type)?
Because Type = new Type.Collared(); calls base constructor public Shirt() { }, not public Shirt(string type), so ProblemVariable is not assigned.
Here is my generic method from which i want to return the class object
public class TestBase
{
public T NavigateandReturntheObject<T>() where T : new()
{
//do navigate to page stuff and return the page object
//previously it was - return new T();
//Now i want to do something like this
return PageObjectBase<T>.PageObject;
}
}
Above method calling the below static generic class which will handle object creation of a particular class
public static class PageObjectBase<T> where T : class, new()
{
private static T singleTonObject;
public static T PageObject
{
get
{
return InstanceCreation();
}
}
public static T InstanceCreation()
{
if (singleTonObject == null)
{
singleTonObject = new T();
}
return singleTonObject;
}
}
How can i call the PageObject property from my test base class please advice.
Note : I have searched forum and find answers relevant to generic method to another generic method calling.The same is achieved by reflection.Can we use reflection in my case too? If so how can we do it.
You can add another constraint 'class' to NavigateandReturntheObject
public T NavigateandReturntheObject<T>() where T : class,new()
Complete Code.
public class TestBase
{
public T NavigateandReturntheObject<T>() where T : class,new()
{
//do navigate to page stuff and return the page object
//previously it was - return new T();
//Now i want to do something like this
return PageObjectBase<T>.PageObject;
}
}
Demo Code
public class TestClass
{
public string Name{get;set;}
public TestClass()
{
Name = "Dummy Name";
}
}
var testBase = new TestBase();
var sample = testBase.NavigateandReturntheObject<TestClass>();
Console.WriteLine(sample.Name);
Output
Dummy Name
I have the following code:
public interface IMyActionFactory
{
AbstractAction<T> CreateAction<T>(MyActionParamBase paramBase = null)
where T : MyActionParamBase;
}
public sealed class MergeActionParam : MyActionParamBase
{
}
public class MergeTest
{
private readonly IMyActionFactory _actionFactory = new DefaultMyActionFactory();
[Theory]
[PropertyData("MergeWorksData")]
public void MergeWorks(/*params here*/)
{
var param = new MergeActionParam();
// populate param here
var sut = _actionFactory.CreateAction<MergeActionParam>(param);
sut.DoAction();
}
}
I am getting an error
"..Error 10 Using the generic type 'IMyActionFactory' requires 1
type arguments..."
Why does the compiler expect a type to be passed to my IMyActionFactory, since I have declared the interface without a T? As far as the method is concerned its the only one to expect the type. Am I missing something here?
How can I make it work without redefining the interface signature?
EDIT:
Feeling a bit embarassed here, because the quick code I put down and ran seperately in a standalone online c# compiler doesnt give any compilation errors. However, going back to my original solution (tens of projects altogether) the error is still there.. Maybe has something to do with the XUnit ?..not sure
public interface IMyActionFactory
{
AbstractAction<T> CreateAction<T>(MyActionParamBase paramBase = null)
where T : MyActionParamBase;
}
public interface IAction
{
void DoAction();
}
public abstract class AbstractAction<T> : IAction
where T : MyActionParamBase
{
public void DoAction()
{
}
}
public class MyActionParamBase
{
public MyActionParamBase()
{
}
}
public sealed class MergeActionParam : MyActionParamBase
{
}
public class DefaultMyActionFactory : IMyActionFactory
{
public AbstractAction<T> CreateAction<T>(MyActionParamBase paramBase = null) where T : MyActionParamBase
{
return null;
}
}
public class MergeTest
{
private readonly IMyActionFactory _actionFactory = new DefaultMyActionFactory();
public void MergeWorks(/*params here*/)
{
var param = new MergeActionParam();
// populate param here
var sut = _actionFactory.CreateAction<MergeActionParam>(param);
sut.DoAction();
}
}
Please check the following section of code (Simplified version)
my concern is in the ReadPath class where I need to call the GetPath() of the type i am using. How can I achieve this?
public interface IPath
{
string GetPath();
}
public class classA: IPath
{
string GetPath()
{
return "C:\";
}
}
public class classB: IPath
{
string GetPath()
{
return "D:\";
}
}
public class ReadPath<T> where T : IPath
{
public List<T> ReadType()
{
// How to call GetPath() associated with the context type.
}
}
public interface IPath
{
string GetPath();
}
public class classA : IPath
{
public string GetPath()
{
return #"C:\";
}
}
public class classB : IPath
{
public string GetPath()
{
return #"D:\";
}
}
public class ReadPath<T> where T : IPath, new()
{
private IPath iPath;
public List<T> ReadType()
{
iPath = new T();
iPath.GetPath();
//return some list of type T
}
}
Interfaces are instance based. So if you want to do that, pass in an instance and work with that.
However, there is a concept that is type-based: attributes:
[TypePath(#"C:\")]
public class classA
{
}
[TypePath(#"D:\")]
public class classB
{
}
public class ReadPath<T>
{
public static List<T> ReadType()
{
var attrib = (TypePathAttribute)Attribute.GetCustomAttribute(
typeof(T), typeof(TypePathAttribute));
var path = attrib.Path;
...
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct
| AttributeTargets.Interface | AttributeTargets.Enum,
AllowMultiple = false, Inherited = false)]
public class TypePathAttribute : Attribute
{
public string Path { get; private set; }
public TypePathAttribute(string path) { Path = path; }
}
Another solution is instance member, but you should change a declaration of generic a little bit:
public class ReadPath<T> where T : IPath, new() //default ctor presence
{
T mem = new T();
public string ReadType()
{
return mem.GetPath();
}
}
Not that I changed returned type as it's not clear how you gonna fit return type string with List<T>
You are confusing between few different aspects of .net/c# programing.
Static methods (which you dont even have here) cannot be defined via interfaces, so if you're interested in using static methods, the interface wotn help you, and you could execute such method in a generic way only by means of reflection.
Your code is abit not clear, hard to understand why your readtype method returns a list, and how are you supposed to fill up this list.