actually i refactor some portion of code.
what i want to do is to initialize an object "Task" with an object "TaskArgument".
let s say "TaskArgument" is abstract and "Task" implements a method "OnEnterTask(TaskArgument args)" and is sealed (for some special behavior of the existing system, which is out of scope).
old code:
public sealed class Task : SomeSystemBaseTask {
private int accessMe;
private int meToo;
public void OnEnterTask(TaskArgument args) {
if (args is SimpleTaskArgument) {
accessMe = ((SimpleTaskArgument)args).uGotIt;
meeToo = 0;
} else if (args is ComplexTaskArgument) {
accessMe = ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier;
meToo = ((ComplexTaskArgument)args).multiplier - 1;
}
}
}
what would be the best practise avoid the typecheck?
my first stupud thought was:
public abstract class TaskArgument {
internal public abstract Initialize(Task args);
}
public class SimpleTaskArgument : TaskArgument {
public int uGotIt = 10;
internal public Initialize(Task task){
task.accessMe = uGotIt;
}
}
public class ComplexTaskArgument : TaskArgument {
public int uGotItValue = 10;
public int multiplier = 10;
internal public Initialize(Task task){
task.accessMe = uGotItValue*multiplier;
task.meToo = multiplier - 1;
}
}
public sealed class Task : SomeSystemBaseTask {
public int accessMe;
public int meToo;
public void OnEnterTask(TaskArgument args){
args.Initialize(this);
}
}
but then my "accessMe" is public and the "Initialize" method works only with "Task".
so i moved the typechecking to another place (in future).
is there any best practise or good design idea.
..."internal public"... mmhhmm?
another crazy idea was an inner class, but i dont like those and it make such a simple case more complex or don't:
public abstract class TaskArgument {
internal public abstract Initialize(ITaskWrapper wrapper);
}
public class SimpleTaskArgument : TaskArgument {
...
}
public class ComplexTaskArgument : TaskArgument {
...
}
public interface ITaskWrapper {
public int AccessIt { set; get; }
...
}
public sealed class Task : SomeSystemBaseTask {
private int accessMe;
...
class TaskWrapper : ITaskWrapper {
...
}
public void OnEnterTask(TaskArgument args){
args.Initialize(new TaskWrapper(this));
}
}
where is the best place for initialization when it is based on the given Type of the "TaskArgument"?
kindly excuse my bad english knowledge
greetings
mo
Use an interface.
public void OnEnterTask(TaskArgument args) {
if (args is SimpleTaskArgument) {
accessMe = ((SimpleTaskArgument)args).uGotIt;
} else if (args is ComplexTaskArgument) {
accessMe = ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier;
}
}
becomes
public void OnEnterTask(ITaskArgument args) {
accessMe = args.GetAccessMe();
}
Then you have your classes implement ITaskArgument and implement the method for each class. In general, when you're doing something like this:
accessMe = ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier;
where you're accessing multiple properties on an object to perform a calculation, it usually makes sense to push that logic into the class itself.
Sounds like you want to put the logic associated with each sub-class of TaskArgument onto that class. You could add an abstract method to TaskArgument called Calculate that has the sub-class specific calculation. That would remove the need for your if statements completely:
public class Task {
private int accessMe;
public void OnEnterTask(TaskArgument args)
{
accessMe = args.Calculate();
}
}
You would then put the multiplication or whatever is appropriate into each sub-class.
I would create a public interface, which only exposes the Intialize method. Do your calculations in your derived classes e.g.
public interface ITaskArgument
{
void Initialize(Task task);
}
public abstract class TaskArgument : ITaskArgument
{
protected int _value;
public class TaskArgument(int value)
{
_value = value;
}
public abstract void Initialize(Task task);
}
public class SimpleTaskArgument : TaskArgument, ITaskArgument
{
public SimpleTaskArgument(int value)
: base (value)
{
}
public override void Initialize(Task task)
{
task.AccessMe = _value;
}
}
public class ComplexTaskArgument : TaskArgument, ITaskArgument
{
private int _multiplier;
public ComplexTaskArgument(int value, int multiplier)
: base (value)
{
_multiplier = multiplier;
}
public override void Initialize(Task task)
{
task.AccessMe = _value * _multiplier;
}
}
public class Task
{
public Task()
{
}
public int AccessMe { get; set; }
public void OnEnterTask(ITaskArgument args)
{
args.Initialize(this);
}
}
example
SimpleTaskArgument simpleArgs = new SimpleTaskArgument(10);
ComplexTaskArgument complexArgs = new ComplexTaskArgument(10, 3);
Task task = new Task();
task.OnEnterTask(simpleArgs);
Console.WriteLine(task.AccessMe); // would display 10
task.OnEnterTask(complexArgs);
Console.WriteLine(task.AccessMe); // would display 30
OK, changed my answer a bit in light of the changing requirements appearing in the comments! (Sheesh, scope creep or what?!)
public class Task
{
public int Variable1 { get; internal set; }
public int Variable2 { get; internal set; }
public void OnEnterTask(ITaskInitializer initializer)
{
initializer.Initialize(this);
}
}
public interface ITaskInitializer
{
void Initialize(Task task);
}
public class SimpleTaskInitializer : ITaskInitializer
{
private int uGotIt = 10;
public void Initialize(Task task)
{
task.Variable1 = uGotIt;
}
}
public class ComplexTaskInitializer : ITaskInitializer
{
private int uGotIt = 10;
private int multiplier = 10;
public void Initialize(Task task)
{
task.Variable1 = uGotIt;
task.Variable2 = uGotIt * multiplier;
// etc - initialize task however required.
}
}
You could create overloads of Task as one option:
public class SimpleTask : Task
{
public override void EnterTask(TaskArgument arg)
{
var s = (SimpleTaskArgument)arg;
}
}
So each task type deals with an equivalent argument type. Or, you can move the logic to a TaskFactory with a static method that returns an int, and has the type checking argument there.
public static class TaskFactory
{
public static int GetVal(TaskArgument arg)
{
if (args is SimpleTaskArgument) {
return ((SimpleTaskArgument)args).uGotIt;
} else if (args is ComplexTaskArgument) {
return ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier;
}
}
}
Your interface implementation also would work; I wouldn't discount that... or define an abstract method within Taskargument, that each overrides to return the value.
HTH.
Related
consider the following game code:
public class Player : MonoBehaviour {
public void UseItem(Item item) {
item.Use(this);
}
public void GetDrunk() {}
}
public class Item {
public WhatInterface[] itemUsages;
public void Use(Player player) {
foreach(var usage in itemUsages) {
usage.Execute(new ItemUsageArgs {itemUser = player, itemUsed = this})
}
}
}
public class GameManager : MonoBehaviour {
public Player mainCharacter;
public Item beer = new Item {itemUsages = new [] {
new TestConsole(),
new DamageFromItem (),
new DrunkFromITem ()
}}
private void Start() {
mainCharacter.Use(beer);
}
}
public class TestConsole : WhatInterface {
public void Execute(BaseArgs args) {
Debug.Log("function call executed");
}
}
public class DamageFromItem : WhatInterface {
public void Execute(ItemUsageArgs args) {
Debug.Log(args.itemUser + " take damage from " + args.itemUsed);
}
}
public class DrunkFromITem : WhatInterface {
public void Execute(ItemUsageArgs args) {
args.itemUser.GetDrunk();
}
}
public class BaseArgs {}
public class ItemUsageArgs : BaseArgs {
public Player itemUser;
public Item itemUsed;
}
so how to create interface type code that is suited for itemUsages?
Or do I wrongly create the design for this context?
Basically I'm trying strategy pattern so that item usages could be vary for every kind of item.
Things I tried, creating IItemUsage interface:
public interface IItemUsage {
void Execute(ItemUsageArgs args);
// but then anything that needs to implement this interface must use this method, even though it only needs BaseArgs.
// TestConsole class must conform to Execute(ItemUsageArgs) signature..
}
public class TestConsole : IItemUsage {
public void Execute(BaseArgs args) {
Debug.Log("function call executed");
}
// this won't compile
}
Assuming this is all of your code, you can make IItemUsage generic, and contravairant on the generic parameter.
public interface IItemUsage<in T> where T: BaseArgs {
void Execute(T args);
}
Have TestConsole implement IItemUsage<BaseArgs> and the other two classes implement IItemUsage<ItemUsageArgs>.
Now you can put instances of all three classes into an IItemUsage<ItemUsageArgs>[]:
IItemUsage<ItemUsageArgs>[] arr = new IItemUsage<ItemUsageArgs>[] {
new TestConsole(), new DamageFromItem(), new DrunkFromITem()
};
If you want to implement interface with some method, which has input arguments, that can be different types, you must define base argument class or use interface parameter instead.
For example:
public interface IItemUsage
{
void Execute(IItemUsageArgs args);
}
public interface IItemUsageArgs
{
//place public part of all ItemUsageArgs
}
public class ItemUsageArgs1 : IItemUsageArgs
{
}
public class ItemUsageArgs2 : IItemUsageArgs
{
}
public class ItemUsage1 :IItemUsage
{
public void Execute(ItemUsageArgs1 args)
{
//do you need
}
void IItemUsage.Execute(IItemUsageArgs args)
{
Execute(args as ItemUsageArgs1);
}
}
public class ItemUsage2 : IItemUsage
{
public void Execute(ItemUsageArgs2 args)
{
//do you need
}
void IItemUsage.Execute(IItemUsageArgs args)
{
Execute(args as ItemUsageArgs2);
}
}
I have a abstract base class, starting a timer which is common to all derived class,
public abstract class BaseClass
{
public virtual void Start() { _timer.Start(); }
}
Now I need to load different JSON configuration files for each derived class and create the file,
public class DerivedClass1 : BaseClass
{
private readonly List<config> configs = new List<config>();
public DerivedClass1()
{
configs = JsonSettings.GetConfigurations(#"./Configurations/1.json");
}
public override void Start()
{
base.Start();
foreach (var configuration in configs)
{
JsonSettings.CreateConfigFile(configuration);
}
}
}
public class DerivedClass2 : BaseClass
{
private readonly List<config> configs = new List<config>();
public DerivedClass2()
{
configs = JsonSettings.GetConfigurations(#"./Configurations/2.json");
}
public override void Start()
{
base.Start();
foreach (var configuration in configs)
{
JsonSettings.CreateConfigFile(configuration);
}
}
}
As I see there are lots of codes are duplicated in various derived class.
Can I move these piece of code as well as abstract base class or is there another way?
I think you could simplify your code to this:
public abstract class BaseClass
{
protected virtual List<config> configs { get; set; } = new List<config>();
public virtual void Start()
{
_timer.Start();
foreach (var configuration in configs)
{
JsonSettings.CreateConfigFile(configuration);
}
}
}
public class DerivedClass1 : BaseClass
{
public DerivedClass1()
{
configs = JsonSettings.GetConfigurations(#"./Configurations/1.json");
}
}
public class DerivedClass2 : BaseClass
{
public DerivedClass2()
{
configs = JsonSettings.GetConfigurations(#"./Configurations/2.json");
}
}
public interface BaseClass
{
void Start();
}
public interface IBaseClassUtil
{
void Start();
void setConfigs(List<config> configs);
}
public class BaseClassUtil : IBaseClassUtil
{
System.Timers.Timer _timer;
public List<config> _configs { get; set; } = new List<config>();
public void Start()
{
_timer.Start();
foreach (var configuration in _configs)
{
JsonSettings.CreateConfigFile(configuration);
}
}
public void setConfigs(List<config> configs)
{
_configs = configs;
}
}
public class DerivedClass1 : BaseClass
{
private IBaseClassUtil _baseUtility;
public DerivedClass1(IBaseClassUtil baseUtility)
{
_baseUtility = baseUtility;
_baseUtility.setConfigs( JsonSettings.GetConfigurations(#"./Configurations/1.json"));
}
public void Start()
{
_baseUtility.Start();
}
}
public class DerivedClass2 : BaseClass
{
private IBaseClassUtil _baseUtility;
public DerivedClass2(IBaseClassUtil baseUtility)
{
_baseUtility = baseUtility;
_baseUtility.setConfigs(JsonSettings.GetConfigurations(#"./Configurations/2.json"));
}
public void Start()
{
_baseUtility.Start();
}
}
This might be oveer engineered. Or might not suit ur current requirement.
Advantages would be
In future if you want u want to have different implementation for IBaseClassUtil it will be easier
And huge advantage would be this code is testable
If the classes differ by nothing but the configuration path, then you can have only one derived class that takes the path as a parameter in its ctor.
public DerivedClass(string configurationPath)
{
configs = JsonSettings.GetConfigurations(configurationPath);
}
Put please note that a decision on including inheritance in your architecture is not about code duplication, and by not giving us any information on the functions or even names of the classes (BaseClass and DerivedClass mean nothing. What do they represent? What's their function? Why are they related?) you give us no way of really helping you with your design.
I would not be surprised if this has been answered somewhere, the problem is I am not sure how to phrase a search to find what I need. The things I have already found have either been too simplistic to be usable or poorly explained such that I cannot translate it into my own project. I had no formal instruction with event handlers, delegates, and the like (heck, I didn't even learn about Entity-Component Systems--or other design patterns--until long after I graduated college and was already employed as a programmer, and even then it wasn't something I learned at, or for, my job).
Essentially what I want to know is, what does the definition of Array.Sort<T>(T[] array, Comparison<T> comparison) look like?
There's clearly some kind of generalization going on, as myCompareDelegate(...) takes two arguments of any type. In almost everything I've found relating to Func arguments, a Func<> parameter requires explicitly declared types, with the exception of some sample code using an operator I am unfamiliar with:
SomeUtility(arg => new MyType());
public void SomeUtility<T>(Func<object, T> converter) {
var myType = converter("foo");
}
It compiles but I have no idea what it does and as such, I do not know how to utilize it to create code that will run or do what I want to do.
My goal here is to be able to create an event system (yes, I'm aware that C# has an event system built in, but again, all the sample code I've seen is either simplified to the point of uselessness--listeners contained in the same class as the dispatcher--or complicated and unexplained). I want the following to be true:
a single function to register an event listener (for any Type of event and its subtypes)
a single function to dispatch an event (calling only the relevant listeners)
to be able to create new event types without having to modify the functions for registration and handling (no explicit types in the dispatcher beyond the base event class) provided the new event type extends the allowable event type (i.e. an Entity will only dispatch EntityEvents not WorldEvents).
I have a system that works currently, but it requires that all my handlers pass through a single "onEvent" function which takes a base event object and figures out what it's actual type is, passing that off to the true handler.
Eg:
//Entity implements IEventDispatcher
public SomeConstructor(Entity ent) {
//public delegate void EventListener(EventBase eventData); is declared
//in the IEventDispatcher interface.
ent.attachEvent(typeof(EntityEventPreRender), new EventListener(onEvent));
ent.attachEvent(typeof(EntityEventPostRender), new EventListener(onEvent));
}
//EntityEventPreRender extends EntityEventRender extends EntityEvent extends EventBase
//EntityEventPostRender extends EntityEventRender extends EntityEvent extends EventBase
public void onEvent(EventBase data) {
if(data is EntityEventPreRender)
onPre((EntityEventPreRender)data);
if(data is EntityEventPostRender)
onPost((EntityEventPostRender)data);
}
public void onPre(EntityEventPreRender evt) {}
public void onPost(EntityEventPostRender evt) {}
attachEvent() here is a function that takes a Type (used as a HashMap key) and a Delegate and stores it in a list (the HashMap value). Dispatching the event just needs to pass the EventData object, which is queried for its type (via evt.GetType()) to retrieve the list of listeners, then invoking them: listItem(evt)
But I'd rather be able to just do this:
public SomeConstructor(Entity ent) {
ent.attachEvent(onPre);
ent.attachEvent(onPost);
}
public void onPre(EntityEventPreRender evt) {}
public void onPost(EntityEventPostRender evt) {}
But I cannot, for the life of me, figure out how to do this because I do not know how to declare the attachEvent() function to take a generic function parameter the way Array.Sort<T>(T[] array, Comparison<T> comparison) does. I get the error:
"The type arguments for method doSomething<T>(SomeClass.Thing<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly."
I think you might be looking for something like the following:
public static class PubSub<TMessage>
{
private static List
<
Action
<
TMessage
>
> listeners = new List<Action<TMessage>>();
public static void Listen(Action<TMessage> listener)
{
if (listener != null) listeners.Add(listener);
}
public static void Unlisten(Action<TMessage> listener)
{
if (listeners.Contains(listener)) listeners.Remove(listener);
}
public static void Broadcast(TMessage message)
{
foreach(var listener in listeners) listener(message);
}
}
In the above code, using PubSub and specifying a type for TMessage creates a new static class in memory with its own memory space allocated for storing a separate list of listeners. The compiler will ensure that only the substituted type for TMessage and its subclasses will be allowed in that list, provided you consistently use the base type as the type argument for the TMessage type parameter.
You would then use it like so:
public class SomeMessageType
{
public int SomeId;
public string SomeDescription;
}
public class SomePublisher
{
public void DoSomethingCool(string description)
{
var randomizer = new Random();
...
PubSub<SomeMessageType>.Broadcast(new SomeMessageType(){SomeId = randomizer.Next(), SomeDescription = description});
}
}
public class SomeListener
{
static SomeListener()
{
PubSub<SomeMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeMessageType message)
{
// do something with the message
}
}
If you then create another class SomeOtherMessageType which does not inherit from SomeMessageType and make similar calls to it, it will only broadcast to listeners of that specific type.
EDITED:
Here is a full proof of concept that compiles that you can run in a console app to allay any remaining concerns you may have over efficacy of this technique.
using System;
using System.Collections.Generic;
namespace TestPubSub
{
public class Program
{
public static void Main(string[] args)
{
Program.startListeners();
Program.sendTestMessages();
Program.stopConsoleFromExitingImmediately();
}
private static void startListeners()
{
SomeListener.Listen();
SomeOtherListener1.Listen();
SomeOtherListener2.Listen();
}
private static void sendTestMessages()
{
var publisher1 = new SomePublisher();
var publisher2 = new SomeOtherPublisher();
publisher1.DoSomethingCool("Hello world");
publisher2.DoSomethingElse(DateTime.Now);
}
private static void stopConsoleFromExitingImmediately()
{
Console.ReadKey();
}
}
public static class PubSub<TMessage>
{
private static List
<
Action
<
TMessage
>
> listeners = new List<Action<TMessage>>();
public static void Listen(Action<TMessage> listener)
{
if (listener != null) listeners.Add(listener);
}
public static void Unlisten(Action<TMessage> listener)
{
if (listeners.Contains(listener)) listeners.Remove(listener);
}
public static void Broadcast(TMessage message)
{
foreach(var listener in listeners) listener(message);
}
}
public class SomeMessageType
{
public int SomeId;
public string SomeDescription;
}
public class SomeOtherMessageType
{
public DateTime SomeDate;
public Double SomeAmount;
}
public class SomePublisher
{
public void DoSomethingCool(string description)
{
var randomizer = new Random();
PubSub<SomeMessageType>.Broadcast(new SomeMessageType(){SomeId = randomizer.Next(), SomeDescription = description});
}
}
public class SomeOtherPublisher
{
public void DoSomethingElse(DateTime when)
{
var randomizer = new Random();
PubSub<SomeOtherMessageType>.Broadcast(new SomeOtherMessageType(){SomeAmount = randomizer.NextDouble(), SomeDate = when});
}
}
public class SomeListener
{
public static void Listen()
{
PubSub<SomeMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeMessageType message)
{
Console.WriteLine("Attention! SomeMessageType receieved by SomeListener with\r\nid: {0}\r\ndescription: {1}\r\n", message.SomeId, message.SomeDescription);
}
}
public class SomeOtherListener1
{
public static void Listen()
{
PubSub<SomeOtherMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Heads up! SomeOtherMessageType receieved by SomeOtherListener1 with\r\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
public class SomeOtherListener2
{
public static void Listen()
{
PubSub<SomeOtherMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Yo! SomeOtherMessageType receieved by SomeOtherListener2 withr\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
}
EDITED AGAIN (Alternate proof of concept using an instance based pubs):
Here is a proof of concept using an instance based PubSub.
using System;
using System.Collections.Generic;
namespace TestPubSub
{
public class Program
{
private static PubSub<SomeMessageType> pubSub1 = new PubSub<SomeMessageType>();
private static PubSub<SomeOtherMessageType> pubSub2 = new PubSub<SomeOtherMessageType>();
private static SomeListener listener1 = new SomeListener();
private static SomeOtherListener1 listener2 = new SomeOtherListener1();
private static SomeOtherListener2 listener3 = new SomeOtherListener2();
public static void Main(string[] args)
{
Program.startListeners();
Program.sendTestMessages();
Program.stopConsoleFromExitingImmediately();
}
private static void startListeners()
{
Program.listener1.Listen(Program.pubSub1);
Program.listener2.Listen(Program.pubSub2);
Program.listener3.Listen(Program.pubSub2);
}
private static void sendTestMessages()
{
var publisher1 = new SomePublisher(Program.pubSub1);
var publisher2 = new SomeOtherPublisher(Program.pubSub2);
publisher1.DoSomethingCool("Hello world");
publisher2.DoSomethingElse(DateTime.Now);
}
private static void stopConsoleFromExitingImmediately()
{
Console.ReadKey();
}
}
public class PubSub<TMessage>
{
private List
<
Action
<
TMessage
>
> listeners = new List<Action<TMessage>>();
public void Listen(Action<TMessage> listener)
{
if (listener != null) this.listeners.Add(listener);
}
public void Unlisten(Action<TMessage> listener)
{
if (listeners.Contains(listener)) this.listeners.Remove(listener);
}
public void Broadcast(TMessage message)
{
foreach(var listener in this.listeners) listener(message);
}
}
public class SomeMessageType
{
public int SomeId;
public string SomeDescription;
}
public class SomeOtherMessageType
{
public DateTime SomeDate;
public Double SomeAmount;
}
public class SomePublisher
{
private PubSub<SomeMessageType> pubSub;
public SomePublisher(PubSub<SomeMessageType> pubSub) { this.pubSub = pubSub; }
public void DoSomethingCool(string description)
{
var randomizer = new Random();
this.pubSub.Broadcast(new SomeMessageType(){SomeId = randomizer.Next(), SomeDescription = description});
}
}
public class SomeOtherPublisher
{
private PubSub<SomeOtherMessageType> pubSub;
public SomeOtherPublisher(PubSub<SomeOtherMessageType> pubSub) { this.pubSub = pubSub; }
public void DoSomethingElse(DateTime when)
{
var randomizer = new Random();
this.pubSub.Broadcast(new SomeOtherMessageType(){SomeAmount = randomizer.NextDouble(), SomeDate = when});
}
}
public class SomeListener
{
public void Listen(PubSub<SomeMessageType> pubSub)
{
pubSub.Listen(this.SomeMessageEvent);
}
private void SomeMessageEvent(SomeMessageType message)
{
Console.WriteLine("Attention! SomeMessageType receieved by SomeListener with\r\nid: {0}\r\ndescription: {1}\r\n", message.SomeId, message.SomeDescription);
}
}
public class SomeOtherListener1
{
public void Listen(PubSub<SomeOtherMessageType> pubSub)
{
pubSub.Listen(this.SomeMessageEvent);
}
private void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Heads up! SomeOtherMessageType receieved by SomeOtherListener1 with\r\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
public class SomeOtherListener2
{
public void Listen(PubSub<SomeOtherMessageType> pubSub)
{
pubSub.Listen(this.SomeMessageEvent);
}
private void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Yo! SomeOtherMessageType receieved by SomeOtherListener2 withr\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
}
I've inherited a large codebase and I'm trying to implement some new functionality into the framework. Basically, in order to do it the "right" way, I would have to modify the entire structure of the framework. since I'm not the guy who designed the framework, nor am I a mind reader, doing so probably isn't going to happen (although I would really love to redesign it all from scratch myself).
So in order to do what I want, I'm trying to implement a decorator pattern, of sorts. This answer from maliger suggests that what I'm doing below is perfectly valid. However, mono doesn't seem to like it; it complains that T cannot be derived from when I declare HappyDecorator
Please forgive the overly simplistic example, but it gets the point across.
public class HappyObject
{
public virtual void print()
{
Console.WriteLine ("I'm happy");
}
}
public class VeryHappyObject : HappyObject
{
public override void print()
{
Console.WriteLine ("I'm very happy");
}
public void LeapForJoy()
{
Console.WriteLine("Leaping For Joy!");
}
}
public class SuperHappyObject : VeryHappyObject
{
public override void print()
{
Console.WriteLine ("I'm super happy!");
}
public void DieOfLaughter()
{
Console.WriteLine("Me Dead!");
}
}
public class HappyDecorator<T> : T where T : HappyObject
{
public string SpecialFactor { get; set; }
public void printMe()
{
Console.WriteLine (SpecialFactor);
print();
}
}
class MainClass
{
public static void Main (string[] args)
{
HappyDecorator<HappyObject> obj = new HappyDecorator<HappyObject> ();
obj.SpecialFactor = Console.ReadLine();
obj.printMe();
}
}
You're typing HappyDecorator to T, but there's no instance of T to use inside that class.
public class HappyDecorator<T> where T : HappyObject
{
private readonly T _instance;
public HappyDecorator(T instance)
{
_instance = instance;
}
public string SpecialFactor { get; set; }
public void printMe()
{
Console.WriteLine(SpecialFactor);
_instance.print();
}
}
Another alternative is to structure it like this with a generic method instead of a generic class. It's not really a decorator then though:
public class HappyDecorator
{
public string SpecialFactor { get; set; }
public void printMe<T>(T instance) where T : HappyObject
{
Console.WriteLine(SpecialFactor);
instance.print();
}
}
And call like:
HappyDecorator obj = new HappyDecorator();
obj.SpecialFactor = Console.ReadLine();
obj.printMe(new HappyObject());
I think this is what you are trying to do:
public interface IhappyObject
{
void Print();
}
public class HappyObject : IhappyObject
{
private IhappyObject obj;
public HappyObject(IhappyObject obj)
{
this.obj = obj;
}
public void Print()
{
obj.Print();
}
}
public class VeryHappyObject : IhappyObject
{
public void Print()
{
Console.WriteLine("I'm very happy");
}
}
public class SuperHappyObject : IhappyObject
{
public void Print()
{
Console.WriteLine("I'm super happy!");
}
}
static void Main(string[] args)
{
HappyObject obj = new HappyObject(new SuperHappyObject());
obj.Print();
}
I have a private abstract class called TDSeq in which there are some abstract members and non-abstract members. There are 2 derived classes which it gets data from:- private class TDSeqBuy: TDSeq and private class TDSeqSell: TDSeq.
The members from the private abstract class that I am trying to access are private/public bools/doubles/integers.
The data flows from the derived classes through to the private abstract class by protected abstract name {get;}. After which the data is "moved" to the above mentioned private/public bool/doubles/integers.
I would like to access data for read-only purposes from the abstract class to a public class but do not know how to do that. Could someone please help?
private abstract class TDSeq
{
public event SetupCompletedEventHandler SetupCompleted;
protected abstract double TDSTHigh { get; }
protected abstract double TDSTLow { get; }
protected abstract double SetupStopLevel { get; }
public double highesthigh = 0;
public double lowestlow = 0;
public double truerange = 0;
public double setupstoplevel = 0;
// ...
case TDSTStateSetup.Completed:
if( ValidSetup )
{
Print = "ValidExtSetup";
setupCount++;
SetupDrawText();
//Print = NameIndex;
}
else
{
Print = "ExtSetup Finalised";
tdsetupiscompleted = true;
if (tdsetupiscompleted)
{
Print = "tdsetupiscompleted";
}
if (tdsetupdirection == 1)
{
Print = "tdsellsetupiscompleted";
}
if (tdsetupdirection == -1)
{
Print = "tdbuysetupiscompleted";
}
highesthigh = TDSTHigh;
lowestlow = TDSTLow;
truerange = (highesthigh - lowestlow);
setupstoplevel = SetupStopLevel;
stateSetup = TDSTStateSetup.Finished;
}
// ...
}
I'm trying to publicly access the last 5 lines...
You can also use auto properties to acheive the same without using a private field.
e.g.
private abstract class A
{
protected int Number { get; private set; }
}
private class B : A
{
public int GetNumber()
{
return Number;
}
}
Use protected, not private. Also consider composition over inheritance.
Nested classes are not a good idea. It only limits scope. And protected will not save you there.
If you want access to the properties and them only to be read only, store the values in private fields - and give a protected get property to give read only access to the private fields like so:
private abstract class A
{
private int _number = 5;
protected int Number { get { return _number; } }
}
private class B : A
{
public int GetNumber()
{
return Number;
}
}
private class C : A
{
public int GetNumber()
{
return Number;
}
}
If you want to access data via an object of an abstract class A within a method of a separate, public class X, the abstract class has to be visible to X, so it has to be public (or at least internal, when A and X are part of the same assembly):
public class Program
{
static void Main(string[] args)
{
B b = new B();
X.Test(b);
}
// private does not work here if you want to have a parameter of type A in X
public abstract class A
{
private int _number = 5;
public int Number { get { return _number; } }
}
private class B : A
{
}
}
public class X
{
public static void Test(Program.A a)
{
Console.WriteLine(a.Number);
}
}
Top level classes in an assembly can only be public or internal in terms of accessibility, so I'm assuming your private abstract class and it's derived classes are all nested inside some public class, for starters. Correct?
If so, simply access members of the nested private abstract class that are non-abstract and public by first instantiating the private derived classes inside that parent class via say a public property, then simply call the public field from it:
public class TopClass
{
DerivedClass MyDerivedClass;
public int GetDerivedClassPublicField
{
get
{
DerivedClass MyDerivedClass = new DerivedClass();
return DerivedClass.myfield;//here is access to your abstract class field from outside
}
}
// Private classes must be nested
private abstract class AbstractClass
{
public int myfield = 1;
}
private class DerivedClass : AbstractClass
{
... (derived classes inherit the non-abstract field from the abstract parent by default here) ...
}
}
// now call the public top level class property to get the field in the abstract class
TopClass MyTopClass = new TopClass();
int myInt = MyTopClass.GetDerivedClassPublicField;