C# Dynamic object cannot access variable as assigned in base constructor - c#

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.

Related

C# generic class as a generic parameter

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

How to resolve boxing or conversion error for below example?

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}")

Looping over List of different generic types in c#

I have a list comprised of different generic types like such:
public abstract class BaseClass {}
public class BaseChild<T> : BaseClass {
public SomeOtherClass<T> data;
}
List<BaseClass> items;
items.Add(new BaseChild<int>());
items.Add(new BaseChild<bool>());
items.Add(new BaseChild<double>());
I now want to loop over this list and pass the data property of each item of type SomeOtherClass to a field of the same type in another generic class. Something like this
public class GenClass<T> {
public SomeOtherClass<T> assignHere;
}
for(int i=0;i<=items.Count;i++){
// this does not work. It is unable to get data since it is not
// defined in BaseClass and the List is of type BaseClass
items[i].data;
// somehow assign to assignHere field in GenClass<T> since I don't know type
}
I have two questions:
How do I access the data field, since it is only defined on the inheritors but not the parent class? The List I loop over is of Type BaseClass and not BaseChild<T>
How do I assign the data to the assignHere field in the GenClass<T> if I don't know it's Type while looping?
Edit:
Code for SomeOtherClass<T>
public class SomeOtherClass<T>{
public T Value;
public GameEvent<T> event
}
public GameEvent<T>:UnityEvent<T>{
public void Raise(T value){
//does something
}
}
Edit #2: Here is one implementation that I have tried and works. Is this better?
public abstract class BaseButton
{
public string displayText;
public abstract void TriggerButton();
}
public class IntButton : BaseButton
{
public IntEvent triggerEvent;
public int Value;
public override void TriggerButton()
{
triggerEvent.Raise(Value);
}
}
public class IntEvent : BaseGameEvent<int>{}
public abstract class BaseGameEvent<T>{
public void Raise(T value){
// do something
}
}
Thanks!
With reflection :
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
List<BaseClass> items = new List<BaseClass>();
items.Add(new BaseChild<int>());
items.Add(new BaseChild<bool>());
items.Add(new BaseChild<double>());
for (int i = 0; i <= items.Count; i++)
{
var generated = Convert(items[i]);
if (generated is GenClass<int> genInt)
{
Console.WriteLine(genInt?.assignHere?.Value);
}
else if (generated is GenClass<bool> genBool)
{
Console.WriteLine(genBool?.assignHere?.Value);
}
}
}
static object Convert(BaseClass item)
{
var type = item.GetType().GenericTypeArguments[0];
var method = typeof(Program).GetMethod("GenericConvert", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(type);
return method.Invoke(null, new[] { item });
}
static GenClass<T> GenericConvert<T>(BaseChild<T> from)
{
return new GenClass<T> { assignHere = from.data };
}
}

Why do I need to declare the type?

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

Is this the proper use of Action<T>

As I understand Func and Action; An Action does not return a value, and a Func does. In the below example I have a child class create an instance of "SomeContent" and pass a reference back to the parent class. My questions are:
Does this.ContentDelagate(content) pass by reference or by value?
In the below example, should I have used Func as I want a reference to an the instantiated SomeContent object? If so can you provide an example?
namespace DelegateTut
{
class Program
{
static void Main(string[] args)
{
TestClass myTest = new TestClass();
myTest.ContentDelagate += ContentDelegateHandler;
myTest.RunDel();
Console.Write("Press Enter to exit...\n");
Console.ReadLine();
}
public static void ContentDelegateHandler(SomeContent content) {
Console.WriteLine(content.ValueOne);
Console.WriteLine(content.ValueTwo);
}
}
}
public class TestClass {
public TestClass() { }
public Action<SomeContent> ContentDelagate { get; set; }
public void RunDel() {
SendContentToMainThread();
}
public void SendContentToMainThread() {
SomeContent content = new SomeContent {
ValueOne = "Hello",
ValueTwo = "World"
};
this.ContentDelagate(content);
}
}
public class SomeContent {
public String ValueOne { get; set; }
public String ValueTwo { get; set; }
public SomeContent() { }
}
Does this.ContentDelagate(content) pass by reference or by value?
This question is a little confusing. We are dealing with both a getter and a delegate as well. I think its clearer to show:
public void SendContentToMainThread()
{
SomeContent content = new SomeContent
{
ValueOne = "Hello",
ValueTwo = "World"
};
Action<SomeContent> myDel = ContentDelagate;//Property Get
myDel(content);//invoke delegate
Console.WriteLine(content.ValueOne);//refer to this below
}
The handler is called as part of the multicast delegate. The handler is being passed a class which is a reference type. In C# reference and value types are passed by value. The underlying value that is copied could be a value (value type) or a location in memory (reference type).
Because this is a reference type it has reference type behavior:
public static void ContentDelegateHandler(SomeContent content)
{
Console.WriteLine(content.ValueOne);
Console.WriteLine(content.ValueTwo);
content.ValueOne = "updated";
}
Now the modified code above Console.WriteLine(content.ValueOne); will print out the word "updated".
In the below example, should I have used Func as I want a reference to
an the instantiated SomeContent object? If so can you provide an
example?
There's nothing being returned in this case so no you should not use Func. Func does not have any impact whatsoever on your desire to have reference type behavior.

Categories

Resources