Using interface to pass through a method - c#

I've got 2+ objects that come from different inheritance trees, but I'd like them to share a common set of code IMoveable.
The IMoveable interface is looking good, and I'm happy with where I've got with it:
public interface IMoveable
{
/// <summary>
/// The speed the object travells between start and end
/// </summary>
int Speed { get; set; }
/// <summary>
/// The current velocity of the object
/// </summary>
Vector2 Velocity { get; set; }
/// <summary>
/// How far the object has travelled
/// </summary>
int DistanceTravelled { get; set; }
/// <summary>
/// The map the object is traversing
/// </summary>
Map Map { get; set; }
/// <summary>
/// Where the object was when they started moving
/// </summary>
Rectangle StartRectangle { get; set; }
/// <summary>
/// Where the object is right now
/// </summary>
Rectangle CurrentRectangle { get; }
/// <summary>
/// Where the object will be after moving
/// </summary>
Rectangle EndRectangle { get; set; }
/// <summary>
/// What will happen if the object walks to the "EndRectangle"
/// </summary>
Map.CollisionResults CollisionResult { get; set; }
/// <summary>
/// What happens if the object triggers a battle
/// </summary>
Action OnBattle { get; set; }
/// <summary>
/// How the object determines their movement
/// </summary>
Action SetMovement { get; set; }
}
With that interface I have a method:
private static void Move(IMoveable moveableOjb)
{
moveableOjb.Speed = 4;
if (moveableOjb.DistanceTravelled > 0)
{
moveableOjb.DistanceTravelled += moveableOjb.Speed;
if (moveableOjb.DistanceTravelled > Map.TileWidth)
{
moveableOjb.DistanceTravelled = 0;
moveableOjb.Velocity = new Vector2();
}
else
{
return;
}
}
moveableOjb.SetMovement();
if (moveableOjb.Velocity != Vector2.Zero)
{
moveableOjb.StartRectangle = moveableOjb.CurrentRectangle;
moveableOjb.EndRectangle = new Rectangle(
moveableOjb.CurrentRectangle.X + ((int)moveableOjb.Velocity.X * 10),
moveableOjb.CurrentRectangle.Y + ((int)moveableOjb.Velocity.Y * 10),
moveableOjb.CurrentRectangle.Width,
moveableOjb.CurrentRectangle.Height);
moveableOjb.CollisionResult = moveableOjb.Map.GetValue(moveableOjb.EndRectangle);
switch (moveableOjb.CollisionResult)
{
case Map.CollisionResults.None:
break;
case Map.CollisionResults.Colliding:
moveableOjb.Velocity = new Vector2();
break;
case Map.CollisionResults.Battle:
moveableOjb.OnBattle();
moveableOjb.Velocity = new Vector2();
break;
case Map.CollisionResults.OffRight:
case Map.CollisionResults.OffLeft:
case Map.CollisionResults.OffTop:
case Map.CollisionResults.OffBottom:
moveableOjb.Speed = 0;
break;
default:
break;
}
}
if (moveableOjb.Velocity != Vector2.Zero)
moveableOjb.DistanceTravelled += moveableOjb.Speed;
}
The problem I'm facing is this code is just weird. I've gotten a static Move method and I don't know where to put it, and I feel like I've gone about this the completely wrong way.
An alternative I have to this is rewrite my classes so instead of them coming from different inheritance, they are in the same tree. I could do that, but it will take some time to restructure.
I guess my main question is - am I going about this the wrong way, or am I close to following a coding practice that I can't quite figure out?
Example of implementation:
public class ClassA : Sprite, IMoveable
{
// interface implementation
public override Update(GameTime gameTime)
{
// Stuff
Move(this);
// More stuff
}
}
EDIT:
I've been informed that is C# 8 you can have default interface methods. I think that may be exactly what I need!

You are confusing what static means. When a method affects a specific instance, like in this case, it should be non static. This is where the "weirdness" comes from.
Static methods are for general operations or, though with pros and cons, as a surrogate for singletons.
Instead of a static method, define it as a member of the class that implements IMoveable or as a default interface method. With no instance as parameter. That way the instance, this, will be moving. You will be able to move by calling it from that instance, which makes more sense semantically:
IMoveable moveableObj = //constructor here...
moveableObj.Move();
If every class implementing the interface moves in the same way, you can still avoid putting the reference to the instance as a parameter and use this. Perhaps the parameters are best used for information about the movement, if needed.

Related

Avoid non-readonly static fields - Immutability NDepend

I am using NDepend for code analysis and got this warning:
https://www.ndepend.com/default-rules/NDepend-Rules-Explorer.html?ruleid=ND1901#!
This rule warns about static fields that are not declared as read-only.
In Object-Oriented-Programming the natural artifact to hold states that can be modified is instance fields. Such mutable static fields create confusion about the expected state at runtime and impairs the code testability since the same mutable state is re-used for each test.
My code is as follows:
using Cosmonaut;
using Microsoft.Azure.Documents.Client;
using System.Configuration;
using LuloWebApi.Entities;
namespace LuloWebApi.Components
{
/// <summary>
/// Main class that encapsulates the creation of instances to connecto to Cosmos DB
/// </summary>
public sealed class CosmosStoreHolder
{
/// <summary>
/// Property to be initiated only once in the constructor (singleton)
/// </summary>
private static CosmosStoreHolder instance = null;
/// <summary>
/// To block multiple instance creation
/// </summary>
private static readonly object padlock = new object();
/// <summary>
/// CosmosStore object to get tenants information
/// </summary>
public Cosmonaut.ICosmosStore<SharepointTenant> CosmosStoreTenant { get; }
/// <summary>
/// CosmosStore object to get site collection information
/// </summary>
public Cosmonaut.ICosmosStore<SiteCollection> CosmosStoreSiteCollection { get; }
/// <summary>
/// CosmosStore object to get page templates information
/// </summary>
public Cosmonaut.ICosmosStore<PageTemplate> CosmosStorePageTemplate { get; }
/// <summary>
/// CosmosStore object to get pages information
/// </summary>
public Cosmonaut.ICosmosStore<Page> CosmosStorePage { get; }
/// <summary>
/// CosmosStore object to get roles information
/// </summary>
public Cosmonaut.ICosmosStore<Role> CosmosStoreRole { get; }
/// <summary>
/// CosmosStore object to get clients information
/// </summary>
public Cosmonaut.ICosmosStore<Client> CosmosStoreClient { get; }
/// <summary>
/// CosmosStore object to get users information
/// </summary>
public Cosmonaut.ICosmosStore<User> CosmosStoreUser { get; }
/// <summary>
/// CosmosStore object to get partners information
/// </summary>
public Cosmonaut.ICosmosStore<Partner> CosmosStorePartner { get; }
/// <summary>
/// CosmosStore object to get super administrators information
/// </summary>
public Cosmonaut.ICosmosStore<SuperAdministrator> CosmosStoreSuperAdministrator { get; }
/// <summary>
/// Constructor
/// </summary>
CosmosStoreHolder()
{
CosmosStoreSettings settings = new Cosmonaut.CosmosStoreSettings(ConfigurationManager.AppSettings["database"].ToString(),
ConfigurationManager.AppSettings["endpoint"].ToString(),
ConfigurationManager.AppSettings["authKey"].ToString());
settings.ConnectionPolicy = new ConnectionPolicy
{
ConnectionMode = ConnectionMode.Direct,
ConnectionProtocol = Protocol.Tcp
};
CosmosStoreTenant = new CosmosStore<SharepointTenant>(settings);
CosmosStoreSiteCollection = new CosmosStore<SiteCollection>(settings);
CosmosStorePageTemplate = new CosmosStore<PageTemplate>(settings);
CosmosStorePage = new CosmosStore<Page>(settings);
CosmosStoreRole = new CosmosStore<Role>(settings);
CosmosStoreClient = new CosmosStore<Client>(settings);
CosmosStoreUser = new CosmosStore<User>(settings);
CosmosStorePartner = new CosmosStore<Partner>(settings);
CosmosStoreSuperAdministrator = new CosmosStore<SuperAdministrator>(settings);
}
/// <summary>
/// Instance access, singleton
/// </summary>
public static CosmosStoreHolder Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new CosmosStoreHolder();
}
return instance;
}
}
}
}
}
However I am not sure how to fix this warning.
This is a guide, not a hard rule. Usually, non-readonly static fields are hard to intuit about. But in this case you're doing lazy deferred loading, so... a lock and mutate is indeed one way of achieving that, without causing it to be loaded prematurely.
So a pragmatic fix is: just ignore/override the warning
Another approach, however, is to move the field to another type where it is readonly, and rely on the deferred .cctor semantics:
public static CosmosStoreHolder Instance {
[MethodImpl(MethodImplOptions.NoInlining)]
get => DeferredHolder.Instance;
}
private static class DeferredHolder {
internal static readonly CosmosStoreHolder Instance = new CosmosStoreHolder();
}
Then you don't even need the lock semantics (.cctor deals with that for you).

Setting properties from another class

I want to pinpoint I'm totally new to C# and I'm just testing around to get a grasp of this language.
Want I want to achieve is to just console-print in a secondary window a couple of values I've set in the MainWindow.
This is a function contained in the MainWindow class, triggered by a button click.
private void ValidationExecuted(object sender, ExecutedRoutedEventArgs eventArgs)
{
// If the validation was successful, let's open a new window.
GeneratorWindow generatorWindow = new GeneratorWindow();
generatorWindow.TextBlockName1.Text = this.tbPoints.Text;
generatorWindow.TextBlockName2.Text = this.tbPDC.Text;
int.TryParse(this.tbPoints.Text, out int numberOfPoints);
int.TryParse(this.tbPDC.Text, out int pdc);
// Those lines correctly print the values I've inserted in the TextBoxes.
Console.WriteLine(numberOfPoints);
Console.WriteLine(pdc);
generatorWindow.NumberOfPoints = numberOfPoints;
generatorWindow.MainPDC = pdc;
generatorWindow.Show();
// Resetting the UI.
this.validator = new Validator();
this.grid.DataContext = this.validator;
eventArgs.Handled = true;
}
Now my secondary window:
public partial class GeneratorWindow : Window
{
/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:ABB_Rapid_Generator.GeneratorWindow" /> class.
/// </summary>
public GeneratorWindow()
{
this.InitializeComponent();
// Those lines just print a pair of 0.
Console.WriteLine(this.NumberOfPoints);
Console.WriteLine(this.MainPDC);
}
/// <summary>
/// Gets or sets the number of points.
/// </summary>
public int NumberOfPoints { private get; set; }
/// <summary>
/// Gets or sets the main PDC.
/// </summary>
public int MainPDC { private get; set; }
}
As you can see in the code comments, the Console.WriteLine() contained in the main class are correctly working. Moreover I can assign my custom values to the TextBlocks contained in the other class. On the contrary, the Console.WriteLine() lines in the secondary class are just outputting a couple of zeros.
What have I been missing?
The problem is that in GeneratorWindow you are writing to the console in the constructor method, so the values are being output before you are changing them.
The only way you can really get that output to work would be to pass the values as parameters of the constructor and set them (in the constructor) before you do the console output. Though there doesn't seem any logical reason to go down that path.
For example:
public GeneratorWindow(int numberOfPoints, int mainPdc)
{
this.InitializeComponent();
this.NumberOfPoints = numberOfPoints;
this.MainPDC = mainPdc;
Console.WriteLine(this.NumberOfPoints);
Console.WriteLine(this.MainPDC);
}
Alternatively, if you want to see the values after you set them, then you will need to move your console outputs to another function that you call after you have set the values.
For example, add this function to GeneratorWindow:
public void OutputValues()
{
Console.WriteLine(this.NumberOfPoints);
Console.WriteLine(this.MainPDC);
}
Which you can then call after you have set the values in your other class:
GeneratorWindow generatorWindow = new GeneratorWindow();
generatorWindow.NumberOfPoints = numberOfPoints;
generatorWindow.MainPDC = pdc;
generatorWindow.OutputValues();
you can add a parameter-ize constructor to do so
public partial class GeneratorWindow : Window
{
//Private members
int m_numberOfPoints;
int m_mainPDC;
/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:ABB_Rapid_Generator.GeneratorWindow" /> class.
/// </summary>
public GeneratorWindow(int mainPDC,int numberOfPoints)
{
this.InitializeComponent();
this.m_mainPDC = mainPDC;
this.m_numberOfPoints = numberOfPoints;
}
/// <summary>
/// Gets or sets the number of points.
/// </summary>
public int NumberOfPoints
{
get{ return m_numberOfPoints; }
set{ m_numberOfPoints = values; }
}
/// <summary>
/// Gets or sets the main PDC.
/// </summary>
public int MainPDC
{
get{ return m_mainPDC; }
set{ m_mainPDC= values; }
}
public void Print()
{
Console.WriteLine(this.NumberOfPoints);
Console.WriteLine(this.MainPDC);
}
}
also this is a constructor so it will be just called at
GeneratorWindow generatorWindow = new GeneratorWindow();//here
Change the secondary window call to
generatorWindow = new GeneratorWindow(pdc,numberOfPoints);
generatorWindow.Print();
Also, your code is not done in a good way IMO, why set values like this?
generatorWindow.TextBlockName1.Text = this.tbPoints.Text;
generatorWindow.TextBlockName2.Text = this.tbPDC.Text;
If you have private variables set just as above sample you can perform all converting, printing and , receiving console output in same class.you'll need to just call the constructor and print method.
Answer above is correct, but there is an alternative.
You can use setter methods like setNumberOfPoints, setMainPDC and print co console after setting the value. So in ValidationExecuted you call for a function to set variable, and in that function after setting variable you print it to console. But don't forget to remove printing to console from constructor

C# Check if controls are a value that I can take in a physical board

I've been working on this for a bit, and I've been stuck at this one spot, I can't figure out a way to count the points in the board...
So, first of all, this is a part of the code that makes the cases, in which my tokens are in:
class Case:Control
{
public Point Position { get; set; }
/// <summary>
/// Creates the dimensions for the cases
/// </summary>
public Case()
{
MaximumSize = new Size(50, 50);
MinimumSize = new Size(50, 50);
}
/// <summary>
/// Creates the background for the cases
/// </summary>
public enum DifferentCase
{
Dark,
Pale,
Brown
}
/// <summary>
/// Creates the tokens
/// </summary>
public enum Token
{
Nothing,
White,
Black
}
public DifferentCase ColorCase { get; set; }
public Token ColorToken { get; set; }
public bool IsBlack { get; set; }
And those being my tokens, I have a method that I'm trying to make that counts how many tokens are black and how many are white:
private void CheckPoints(Case cases)
{
foreach (Case case_ in cases.Controls)
{
if (case_.ColorToken == Case.Token.Black)
{
_player1Points++;
lbl_player1Points.Text = _player1Points.ToString();
}
else if (case_.ColorToken == Case.Token.White)
{
_player2Points++;
lbl_player2Points.Text = _player2Points.ToString();
}
}
}
But when I try to call that method in like this: CheckPoints() for example, if I'm clicking on of those cases, it tells me that "There is no argument that corresponds to the required formal parameter "cases" of 'frm_othello.CheckPoints(Case)'"
I don't know if the code that I put in that method is good, neither I don't know why I cant call that method in.
Currently you can't call CheckPoints(); with no arguments. You have defined it with a parameter Case
so you need to do CheckPoints(cases) or whatever is the name of the variable / property / field that has cases

How can I parallelize the merge operation on a bidirectional one-to-many relationship?

I am coding a parallel clustering algorithm in C#. I have a class called Classification which currently uses a Dictionary to associate a String label with a set of N-dimensional points. Each label has one or more points in its cluster. Classification also has a reverse index that associates each point with its label, which is in a second Dictionary.
The most expensive method currently performs many merge operations. A merge takes all members of a source cluster and moves them to the same target cluster. This operation updates both Dictionaries.
I have multiple processes that identify points that belong together in the same cluster. This relationship is transitive: if A belongs with B and B with C, then A, B and C belong in the same cluster. However, there is no easy way to segment the problem such that each process works on a disjoint subset of points. The processes will be operating on the same points.
How do I implement the merge method to minimize lock contention and assure atomic operations? Here is a portion of my class definition. The final method, Merge, is the one I want to parallelize. That may require me to change my Dictionaries into parallel collections.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Cluster
{
/// <summary>
/// Represent points grouped into class partitions where each point is associated with a class label
/// and each labeled class has a set of points.
///
/// This does not perform the unassisted clustering of points.
/// </summary>
/// <typeparam name="TPoint">Type of the points to be classified.</typeparam>
/// <typeparam name="TLabel">Type of the label that can be associated with a set within the classification.</typeparam>
public class Classification<TPoint, TLabel> where TLabel : IEquatable<TLabel>
{
#region Properties (LabelToPoints, PointToLabel, NumPartitions, NumPoints)
/// <summary>
/// Associates a class label with the points belonging to that class.
/// </summary>
public Dictionary<TLabel, ISet<TPoint>> LabelToPoints { get; set; }
/// <summary>
/// Associates a point with the label for its class.
/// </summary>
private Dictionary<TPoint, TLabel> PointToLabel { get; set; }
/// <summary>
/// Total number of class partitions that points are divided among.
/// </summary>
public int NumPartitions { get { return LabelToPoints.Count; } }
/// <summary>
/// Total number of points among all partitions.
/// </summary>
public int NumPoints { get { return PointToLabel.Count; } }
#endregion
#region Constructors
public Classification()
{
LabelToPoints = new Dictionary<TLabel, ISet<TPoint>>();
PointToLabel = new Dictionary<TPoint, TLabel>();
}
public Classification(IEnumerable<TPoint> points, Func<TPoint,TLabel> startingLabel) : this()
{
foreach (var point in points)
{
Add(point, startingLabel(point));
}
}
/// <summary>
/// Create a new Classification by randomly selecting a subset of the points in the current Classification.
/// </summary>
/// <param name="sampleSize">Number of points to include in the new Classification.</param>
/// <returns>A new Classification that has the given number of points.</returns>
public Classification<TPoint, TLabel> Sample(int sampleSize)
{
var subset = new Classification<TPoint, TLabel>();
foreach (var point in Points().TakeRandom(sampleSize, NumPoints))
subset.Add(point, GetClassLabel(point));
return subset;
}
#endregion
#region Modify the Classification (Add, Remove, Merge)
/// <summary>
/// Add a point to the classification with the associated label.
///
/// If the point was already classified, its old classification is removed.
/// </summary>
/// <param name="p">Point to add.</param>
/// <param name="classLabel">Label for classification.</param>
public void Add(TPoint p, TLabel classLabel)
{
Remove(p);
PointToLabel[p] = classLabel;
EnsurePartition(classLabel).Add(p);
}
private ISet<TPoint> EnsurePartition(TLabel classLabel)
{
ISet<TPoint> partition;
if (LabelToPoints.TryGetValue(classLabel, out partition)) return partition;
partition = new HashSet<TPoint>();
LabelToPoints[classLabel] = partition;
return partition;
}
/// <summary>
/// Remove a point from its class.
/// </summary>
/// <param name="p">Point to remove.</param>
/// <returns>True if the point was removed, false if it was not previously a member of any class.</returns>
public Boolean Remove(TPoint p)
{
TLabel label;
if (!PointToLabel.TryGetValue(p, out label)) return false;
PointToLabel.Remove(p);
var oldPoints = LabelToPoints[label];
var didRemove = oldPoints.Remove(p);
if (oldPoints.Count == 0)
LabelToPoints.Remove(label);
return didRemove;
}
/// <summary>
/// Merge all the members of the partitions labeled by any of the labels in sourceLabels
/// into the partition indicated by targetLabel.
/// </summary>
/// <param name="targetLabel">Move members into this labeled partition.</param>
/// <param name="sourceLabels">Move members out of these labeled partitions.</param>
public void Merge(TLabel targetLabel, IEnumerable<TLabel> sourceLabels)
{
var targetPartition = EnsurePartition(targetLabel);
foreach (var sourceLabel in sourceLabels.Where(sLabel => !sLabel.Equals(targetLabel)))
{
ISet<TPoint> singleSourcePoints;
if (!LabelToPoints.TryGetValue(sourceLabel, out singleSourcePoints)) continue;
// Add to LabelToPoints under new targetLabel
targetPartition.UnionWith(singleSourcePoints);
// Remove from LabelToPoints under old sourceLabel.
LabelToPoints.Remove(sourceLabel);
foreach (var p in singleSourcePoints)
PointToLabel[p] = targetLabel;
}
}
#endregion
}
}
UPDATE 1:
I am sure that changing the Dictionaries to ConcurrentDictionary is not enough. I think I need to take out locks on the target label and all the source labels. If any other process is in the middle of performing a merge with any of those labels as source or target, then I need to wait until that other process is done. How do you do this without creating deadlocks? I can sort the labels alphabetically to try and ensure the same order, but is that enough?
UPDATE 2:
New approach. I realized that the merge operations are order independent. I will create a multiple producer, single consumer queue. The producers find opportunities to merge, while the consumer serializes access to the Classification object. Since performing the merges takes longer than finding the merge candidates, the consumer won't starve. A better design would get better throughput, but this will still be an improvement.

Create an Xml file from an object

I work as a web developer with a web designer and we usually do like this :
- I create the system , I generate some Xml files
- the designer display the xml files with xslt
Nothing new.
My problem is that I use Xml Serialization to create my xml files, but I never use Deserialization. So I'd like to know if there is a way to avoid fix like these :
empty setter for my property
empty parameter-less constructor
implement IXmlSerializable and throw "notimplementedexception" on deserialization
do a copy of the class with public fields
Ok mis-read your question first time around! Pretty sure there is no way to avoid this. There has to be a parameterless constructor and you can't serialize readonly properties. I think your only other option is DataContractSerializer.
http://blogs.mastronardi.be/Sandro/2007/08/22/CustomXMLSerializerBasedOnReflectionForSerializingPrivateVariables.aspx
This article describes creating a custom XML serialiser so you can serialise private fields - it may take a little bit of moulding to the form that you want, but it's easier than it looks (honest!) and it's a good start to writing your own serialiser / deserialiser that will serialise exactly what you want - and doesn't care about parameterless constructors or writeable properties.
The only other solution I can think of is to make a wrapper class for every serialisable class - but I don't know how good that would be in the long run. I just get the impression it's not good.
I know you don't want to add a parameterless constructor nor setters, but that's the only way to go with using the XmlSerializer. The good news is the parameterless constructor can be private and the setters can be empty and serialization will work. See thus:
namespace Aesop.Dto
{
using System;
using System.Xml.Serialization;
/// <summary>
/// Represents an Organization ID/Name combination.
/// </summary>
[Serializable]
public sealed class Org
{
/// <summary>
/// The organization's name.
/// </summary>
private readonly string name;
/// <summary>
/// The organization's ID.
/// </summary>
private readonly int id;
/// <summary>
/// Initializes a new instance of the <see cref="Org"/> class.
/// </summary>
/// <param name="name">The organization's name.</param>
/// <param name="id">The organization's ID.</param>
public Org(string name, int id)
{
this.name = name;
this.id = id;
}
/// <summary>
/// Prevents a default instance of the <see cref="Org"/> class from
/// being created.
/// </summary>
private Org()
{
}
/// <summary>
/// Gets or sets the organization's name.
/// </summary>
/// <value>The organization's name.</value>
[XmlAttribute]
public string Name
{
get
{
return this.name;
}
set
{
}
}
/// <summary>
/// Gets or sets the organization's ID.
/// </summary>
/// <value>The organization's ID.</value>
[XmlAttribute]
public int ID
{
get
{
return this.id;
}
set
{
}
}
}
}
Ok now i understand it. I don't think there can be any way to do it with XMLSerialization.
XMLSerialization need these information to re-populate the object. It does not know that some user never deserialize data. You might have to write some code to generate XML for your objects.
class Preferences
{
private const string filePreferences = "preferences.xml";
public Preferences() { }
public static Preferences Load()
{
Preferences pref = null;
if (File.Exists(Preferences.FileFullPath))
{
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(Preferences));
using (var xmlReader = new System.Xml.XmlTextReader(Preferences.FileFullPath))
{
if (serializer.CanDeserialize(xmlReader))
{
pref = serializer.Deserialize(xmlReader) as Preferences;
}
}
}
return ((pref == null) ? new Preferences() : pref);
}
public void Save()
{
var preferencesFile = FileFullPath;
var preferencesFolder = Directory.GetParent(preferencesFile).FullName;
using (var fileStream = new FileStream(preferencesFile, FileMode.Create))
{
new System.Xml.Serialization.XmlSerializer(typeof(Preferences)).Serialize(fileStream, this);
}
}
}

Categories

Resources