I am using a facade design pattern for a C# program. The program basically
looks like this...
public class Api
{
#region Constants
private const int version = 1;
#endregion
#region Private Data
private XProfile _profile;
private XMembership _membership;
private XRoles _role;
#endregion Private Data
public Api()
{
_membership = new XMembership();
_profile = new XProfile();
_role = new XRoles();
}
public int GetUserId(string name)
{
return _membership.GetIdByName(name);
}
}
Now, as I would like subclass my methods into three categories: Role, Profile, and Member.
This will be easier on the developers eye because both Profile and Membership expose a lot of methods that look similar (and a few by Role). For example, getting a user's ID would look like:
int _id = Namespace.Api.Member.GetUserId("Henry222");
Can somebody "illustrate" how subclassing should work in this case to achieve the effect I am looking for?
Thanks in advance.
I would argue that you might mean "inner class" from the context of your question. You might try something like the following...
public class Api
{
public class MemberApi
{
private readonly Api _parent;
internal MemberApi(Api parent) { _parent = parent; }
public int GetUserId(string name)
{
return _parent._membership.GetIdByName(name);
}
}
#region Constants
private const int version = 1;
#endregion
#region Private Data
private XProfile _profile;
private XMembership _membership;
private XRoles _role;
public MemberApi { get; private set; }
#endregion Private Data
public Api()
{
_membership = new XMembership();
_profile = new XProfile();
_role = new XRoles();
Member = new MemberApi(this);
}
}
Related
I have these classes, one is a model, other is Listener and the third one is an Util class. I want to access Terrains by the variable map in the first one, but don't want public access to the inner class Terrain. Is there any way to do it?
It prints error CS0052: Inconsistent accessibility: field type
System.Collections.Generic.List is less
accessible than field `MapaMundiInfoScript.map'
public class MapaMundiInfoScript : MonoBehaviour {
public static bool changeInMap= false;
public static List<Terrain>map = new List<Terrain>();
void Start(){
Terrain terrain = new Terrain(0,0);
Terrain.TerrainPart initialPart = new Terrain.TerrainPart(20,20,0,0);
terrain.terrainParts.Add (initialPart);
map.Add(terrain);
changeInMap=true;
}
class Terrain{
int XPosition;
int ZPosition;
public List <TerrainPart> terrainParts = new List<TerrainPart> ();
public Terrain(int XPosition, int ZPosition){
this.XPosition=XPosition; this.ZPosition=ZPosition;
}
public class TerrainPart
{
int XSize;
int ZSize;
int XPosition;
int ZPosition;
TerrainPartReturn ReturnTerrainPart(int num1,int num2,int num3,int num4)
{
return new TerrainPart (num1,num2,num3,num4);
}
public TerrainPart(int XSize,int ZSize,int XPosition,int ZPosition){
this.XSize = XSize;
this.ZSize = ZSize;
this.XPosition=XPosition;
this.ZPosition =ZPosition;
}
}
}
public class MapListener : MonoBehaviour {
void Update () {
if (MapaMundiInfoScript.changeInMap) {
foreach(MapaMundiInfoScript.Terrain terrain in MapaMundiInfoScript.mapMundi)
{
foreach(terrain.terrainPart terrainPart in terrain.terrainParts)
{
RegionDraw.Draw(terrainPart);
}
}
MapaMundiInfoScript.changeInMap = false;
}
}
public class RegionDraw
{
/***
Implementantion Draw Method
***/
}
You cannot reference a private class as a public property. You will need to have the class public for public access. Consider making your properties and methods private, private protected, internal etc.
If you need to provide read only attributes, you can use public getters and private setters, etc. If you need to prevent the execution of some methods consider setting those to private, etc. The class can be public while still locking down properties and methods inside the class. Consider what it is that you actually need to expose.
You could also expose the functionality of these hidden classes through interfaces
public interface ITerrain
{
List<ITerrainPart> TerrainParts { get; }
ITerrainPart CreateTerrainPart(int XSize, int ZSize, int XPosition, int ZPosition);
}
public interface ITerrainPart
{
// ...
}
Implement them like this
private class Terrain : ITerrain
{
int XPosition;
int ZPosition;
public List<ITerrainPart> TerrainParts { get; } = new List<ITerrainPart>();
public Terrain(int XPosition, int ZPosition)
{
this.XPosition = XPosition; this.ZPosition = ZPosition;
}
public ITerrainPart CreateTerrainPart(int XSize, int ZSize, int XPosition,
int ZPosition)
{
return new TerrainPart(XSize, ZSize, ZPosition, ZPosition);
}
private class TerrainPart : ITerrainPart
{
// ...
}
}
Your listener can then draw like this (after changing the parameter type of Draw to ITerrainPart):
void Update()
{
if (MapaMundiInfoScript.changeInMap) {
foreach (ITerrain terrain in MapaMundiInfoScript.map) {
foreach (ITerrainPart terrainPart in terrain.TerrainParts) {
RegionDraw.Draw(terrainPart);
}
}
MapaMundiInfoScript.changeInMap = false;
}
}
Let MapaMundiInfoScript have a method DrawTerrain() and let Terrain have a method DrawParts. Should you end up with to many incoherent methods in MapaMundiInfoScript, you might want to use a visitor.
I am just looking into implementing an MVVMCross Messenger solution that will enable me to upload information to Google Analytics when published from either the iOS application or the PCL.
The problem I have the is that the subscription delgates are not fired after I publish. Can you subscribe to MVVMCross Messenger subscriptions from a static class?
Subscriptions in static class
public static class GoogleAnalyticsWrapper //: IDisposable
{
private const string TrackingId = "xxxxxxxxxxx";
private static readonly IMvxMessenger messenger;
private static readonly MvxSubscriptionToken screenNameToken;
private static readonly MvxSubscriptionToken eventToken;
private static readonly MvxSubscriptionToken exceptionToken;
private static readonly MvxSubscriptionToken performanceToken;
private static readonly MvxSubscriptionToken publishToken;
private static bool disposed = false;
private static SafeHandle handle;
static GoogleAnalyticsWrapper()
{
Gai.SharedInstance.DispatchInterval = 60;
Gai.SharedInstance.TrackUncaughtExceptions = true;
Gai.SharedInstance.GetTracker(TrackingId);
messenger = new MvxMessengerHub();// Mvx.Resolve<IMvxMessenger>();
screenNameToken = messenger.Subscribe<GaScreenNameMessage>((m) => SetScreenName(m));
int count = messenger.CountSubscriptionsFor<GaScreenNameMessage>();
eventToken = messenger.Subscribe<GaEventMessage>(CreateEvent);
exceptionToken = messenger.Subscribe<GaExceptionMessage>(CreateException);
performanceToken = messenger.Subscribe<GaPerformanceTimingMessage>(CreatePerformanceMetric);
publishToken = messenger.Subscribe<GaPublishMessage>(PublishAll);
}
public static string Dummy { get; set; }
public static void SetScreenName(GaScreenNameMessage message)
{
System.Diagnostics.Debugger.Break();
Gai.SharedInstance.DefaultTracker.Set(GaiConstants.ScreenName, message.ScreenName);
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateScreenView().Build());
}
public static void CreateEvent(GaEventMessage message)
=> Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateEvent(message.Category, message.Action, message.Label, message.Number).Build());
private static void CreateException(GaExceptionMessage message)
=> Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateException(message.ExceptionMessage, message.IsFatal).Build());
private static void CreatePerformanceMetric(GaPerformanceTimingMessage message)
=> Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateTiming(message.Category, message.Milliseconds, message.Name, message.Label).Build());
private static void PublishAll(GaPublishMessage message)
=> Gai.SharedInstance.Dispatch();
public static void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Dispose managed resources.
if (handle != null)
{
handle.Dispose();
}
}
// Dispose unmanaged managed resources.
disposed = true;
}
}
}
Publication
messengerService.Publish<GaEventMessage>(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
The problem is, that you are creating a new MvxMessengerHub in your static class, but (I guess) inject IMvxMessenger in your consuming classes, which is created by MvvMCross during the initialization lifecycle and so a different instance.
The easy solution would be to initialize it in your App.cs like
public class App : Cirrious.MvvmCross.ViewModels.MvxApplication
{
public override void Initialize()
{
// ...
var m = Cirrious.CrossCore.Mvx.Resolve<IMvxMessenger>();
GoogleAnalyticsWrapper.Initialize(m);
// ...
}
}
With a wrapper like this
public static class GoogleAnalyticsWrapper
{
static void Initialize(IMvxMessenger messenger)
{
Gai.SharedInstance.DispatchInterval = 60;
Gai.SharedInstance.TrackUncaughtExceptions = true;
Gai.SharedInstance.GetTracker(TrackingId);
screenNameToken = messenger.Subscribe<GaScreenNameMessage>((m) => SetScreenName(m));
int count = messenger.CountSubscriptionsFor<GaScreenNameMessage>();
eventToken = messenger.Subscribe<GaEventMessage>(CreateEvent);
exceptionToken = messenger.Subscribe<GaExceptionMessage>(CreateException);
performanceToken = messenger.Subscribe<GaPerformanceTimingMessage>(CreatePerformanceMetric);
publishToken = messenger.Subscribe<GaPublishMessage>(PublishAll);
}
// ...
}
Advanced Hint
But as far as I see, you don't even need messaging for this case, because it's one to one "communication". I think it would be nice, if you move the functionality of your GoogleAnalyticsWrapper into a well defined Service like:
interface ITrackingService
{
void SetScreenName(GaScreenNameMessage message);
void CreateEvent(GaEventMessage message);
void CreateException(GaExceptionMessage message);
void CreatePerformanceMetric(GaPerformanceTimingMessage message);
void PublishAll(GaPublishMessage message);
}
public class GoogleAnalyticsTrackingService : ITrackingService
{
private const string TrackingId = "xxxxxxxxxxx";
public GoogleAnalyticsTrackingService()
{
Gai.SharedInstance.DispatchInterval = 60;
Gai.SharedInstance.TrackUncaughtExceptions = true;
Gai.SharedInstance.GetTracker(TrackingId);
}
public void SetScreenName(GaScreenNameMessage message)
{
Gai.SharedInstance.DefaultTracker.Set(GaiConstants.ScreenName, message.ScreenName);
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateScreenView().Build());
}
public void CreateEvent(GaEventMessage message)
{
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateEvent(message.Category, message.Action, message.Label, message.Number).Build());
}
private void CreateException(GaExceptionMessage message)
{
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateException(message.ExceptionMessage, message.IsFatal).Build());
}
private void CreatePerformanceMetric(GaPerformanceTimingMessage message)
{
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateTiming(message.Category, message.Milliseconds, message.Name, message.Label).Build());
}
private void PublishAll(GaPublishMessage message)
{
Gai.SharedInstance.Dispatch();
}
}
That has to be registered in your App
Mvx.LazyConstructAndRegisterSingleton<ITrackingService, GoogleAnalyticsTrackingService>();
And can be consumed with constructor injection or manual resolves
class MyViewModel : MvxViewModel
{
public MyViewModel(ITrackingService tracking)
{
tracking.CreateEvent(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
}
}
// or
class MyViewModel : MvxViewModel
{
public MyViewModel()
{
var tracking = Mvx.Resolve<ITrackingService>();
tracking.CreateEvent(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
}
}
There is still one Problem: The interface has still a dependency to google analytics. But the dependency can be easily removed by using multiple parameters instead of a parameter object.
interface ITrackingService
{
void CreateEvent(string eventName, string title, string message, params object[] additionalParams);
// ...
}
// call:
tracking.CreateEvent("Event", "Publish Event", "Publish Event From First View Model", 123);
With this, you are able to unit test it and exchange the tracking service with litte effort, if your stakeholders decide to switch to adobe omniture or whatever.
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;
I'm sure I've seen somewhere that I can do the following by using an attribute above my Init() method, that tells the compiler that the Init() method must only be called from the constructor, thus allowing the readonly field to be set. I forgot what the attribute is called though, and I can't seem to find it on google.
public class Class
{
private readonly int readonlyField;
public Class()
{
Init();
}
// Attribute here that tells the compiler that this method must be called only from a constructor
private void Init()
{
readonlyField = 1;
}
}
Rob's answer is the way to do it, in my book. If you need to initialize multiple fields you can do it using out parameters:
public class Class
{
private readonly int readonlyField1;
private readonly int readonlyField2;
public Class()
{
Init(out readonlyField1, out readonlyField2);
}
protected virtual void Init(out int field1, out int field2)
{
field1 = 1;
field2 = 2;
}
}
Personally I find this makes sense in certain scenarios, such as when you want your fields to be readonly but you also want to be able to set them differently in a derived class (without having to chain a ton of parameters through some protected constructor). But maybe that's just me.
Instead of using an Initialize method, how about inheriting a basic constructor through all your other constructors.
i.e.
public class MyClass
{
readonly int field1;
readonly double field2;
public MyClass(int field1, double field2)
{
//put whatever initialization logic you need here...
field1 = 10;
field2 = 30.2;
}
public MyClass(int field1, double field2p1, double field2p2)
: this(field1, (field2p1 + field2p2))
{
//put anything extra in here
}
}
This may be a little late to reach the original person in need, but it seems like this will cleanly solve the problem... Without the need to use any sort of nasty reflection or out parameters.
The only solution I can think of is to return the value from the Init() method that the readonly field needs to be assigned:
public class Class
{
private readonly int readonlyField;
public Class()
{
readonlyField = Init();
}
private int Init()
{
return 1;
}
}
Jared is right; this is not possible. The workarounds I can think of are:
Initialize the field in the declaration.
Initialize the field in the constructor (Manually inline your Init method).
Assign the field to a value returned by a method, e.g.: _myField = GetInitialMyFieldValue();
Pass the field to the Init method, with the out modifier. This may be useful if you have many fields to initialize, which are dependent on constructor parameters. E.g.
private readonly int _x;
private readonly string _y;
private void Init(int someConstructorParam, out int x, out string y){ .. }
public Class(int someConstructorParam)
{
Init(someConstructorParam, out _x, out _y);
}
This cannot be done. Fields which are tagged with readonly can only be set from the constructor
What i ended up doing in current tech (C# 7.x) is use the value tuple system:
public class MyClass
{
private readonly int x;
private readonly int y;
private readonly int z;
public MyClass(int x)
{
this.x = x;
(y, z) = InitYandZ();
}
private (int, int) InitYandZ()
{
return (5, 10);
}
}
Not the cleanest either, But seems cleaner to me.
C# compiler only allows you to set readonly fields if you're initializing them inline:
private readonly int readonlyField = 1;
or from the constructor:
public Class()
{
readonlyField = 1;
}
How about an initialized property with a getter only (as of C# 6.0)?
private int MyProperty { get; } = 0;
I know this is late, but what about using a class as a return value instead of using out params if there is a need to initialize multiple fields, are there any drawacks? Imho this is more convenient and more readable than using nested constructors.
public class MyInitClass
{
public int Field1 { get; set; }
public int Field2 { get; set; }
}
public class Class
{
private readonly int readonlyField1;
private readonly int readonlyField2;
public Class()
{
var init = Init();
readonlyField1 = init.Field1;
readonlyField2 = init.Field2;
}
private MyInitClass Init()
{
return new MyInitClass() { Field1 = 1, Field2 = 2 };
}
}
I think it works if use Reflection. Actually this works for me:
public class Class
{
private readonly int readonlyField;
public int MyField()
{
return readonlyField;
}
public Class()
{
readonlyField = 9;
}
}
and
static void Main(string[] args)
{
Class classObj = new Class();
Console.WriteLine(classObj.MyField());//9
Misc.SetVariableyByName(classObj, "readonlyField", 20);//20
Console.WriteLine(classObj.MyField());
}
this is SetVariableByName():
public static b
ool SetVariableyByName(object obj, string var_name, object value)
{
FieldInfo info = obj.GetType().GetField(var_name, BindingFlags.NonPublic| BindingFlags.Instance);
if (info == null)
return false;
/* ELSE */
info.SetValue(obj, value);
return true;
}
the only thing is that readonlyField is public not private. I know that you can edit a private field, but am not sure why its not working for me!
So I try to create opensource C# project for slicing FLVs I began with translating of existing project called flvslicer
Can any one please help me with translating one of their classes
package org.bytearray.video.events
{
import flash.events.Event;
import flash.utils.ByteArray;
public final class MergedEvent extends Event
{
public var time:Number;
public var stream:ByteArray;
public static const COMPLETE:String = "mergeComplete";
public function MergedEvent(type:String, stream:ByteArray, duration:Number)
{
super(type, false, false); // base
this.stream = stream;
this.time = duration;
}
}
}
In C# you have two separate items, an EventHandler<TArgs> declaration and the custom EventArgs subclass.
public event EventHandler<MergedEventArgs> MergeComplete;
public class MergedEventArgs : EventArgs {
public double Time { get; set; }
public byte[] Stream { get; set;
}