I'm implementing a union-find data structure in C#. The elements must extend the Element inner-class, but I'd like to to keep the fields in that class private to the outside world. They need to be public to the direct outer-class, however. The folloowing code does not compile due to "inconsistent accessibility":
class DisjointSetForrests<T> where T : DisjointSetForrests<T>.Element {
private class PrivateElement {
public Element p;
public int rank;
}
public class Element : PrivateElement {
}
public void MakeSet(T x) {
x.p = x;
x.rank = 0;
}
public T FindSet(T x) {
if (x != x.p) x.p = FindSet(x);
return (T)x.p;
}
public void Union(T x, T y) {
Link(FindSet(x), FindSet(y));
}
public void Link(T x, T y) {
if (x.rank > y.rank) {
y.p = x;
} else {
x.p = y;
if (x.rank == y.rank) y.rank++;
}
}
}
Is there a way to achieve what I want, or should I accept the fields in Element being public?
It's not possible to keep them only public to the outer class.
The question is why do you need to keep them public? If you creating a library you could use internal.
Related
This question already has answers here:
Why not inherit from List<T>?
(27 answers)
Closed 2 years ago.
Problem
I have Point2D class as a base class, to store List of Points I normally use List<Point2D> but now I want to Add Additional Methods and Few Properties to List<Point2D> like ToString Method for Printing, sorting based on the specific coordinate, specific method to filter Points, I don't want to use Extention Methods.
Things I Tried
I made a new Point2DList Class who inherits List<Point2D> class which is working fine for normal use but when using FindAll Function it now returns List<Point2D> but I want it to return Point2DList.I know I can write my own method which accepts predicate delegate but that's too much work.
Code
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleAppTest
{
internal static class Program
{
private static void Main()
{
try
{
var points = new Point2DList();
points.Add(new Point2D(0, 0));
points.Add(new Point2D(10, 0));
points.Add(new Point2D(10, 10));
points.Add(new Point2D(0, 10));
Console.WriteLine(points.ToString());
Point2DList newPoints = points.FindAll((x) => x.X == 10);
}
catch (Exception)
{
throw;
}
finally
{
Console.ReadLine();
}
}
}
public class Point2DList : List<Point2D>
{
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine("List of Points");
foreach (var pt in this)
{
sb.AppendLine(pt.ToString());
}
return sb.Remove(sb.Length - 1, 1).ToString();
}
}
public class Point2D
{
public int X { get; set; }
public int Y { get; set; }
public Point2D(int x, int y)
{
X = x;
Y = y;
}
public override string ToString()
{
return $"{X},{Y}";
}
}
}
It´s rarely neccessary to inherit from any collection-type - in particular as you just want to extent it, not change its implementation. Thus I´d go for composition over inheritance and use a field instead:
class Points2DList
{
private List<Point2D> _points;
public Points2DList(List<Point2D> points) { _points = points; }
public override string ToString() { ...}
public void Add(Point2D p { _points.Add(p); } // delegate to implementation of your underlying list
public Point2D this[int i] // delegate to implementation of your underlying list
{
get => _points[i];
set => _points[i] = value;
}
public Points2DList FindAll(Predicate<Point2D> P)
{
return new Points2DList(_list.FindAll(p));// delegate to implementation of your underlying list
}
}
This way you can control which functionality you really want to expose to clients. Using inheritance would expose every public member to the outside, which you probably don´t want. E.g. while you want to allow removing an element from your list, you may not want to enable clients to call Clear on it.
Another option is to just pass it to a new list. In Linq, the same thing happens when you for example call AsReadOnly or ToList etc.
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleAppTest
{
public static class Program
{
public static void Main()
{
try
{
var points = new Point2DList();
points.Add(new Point2D(0, 0));
points.Add(new Point2D(10, 0));
points.Add(new Point2D(10, 10));
points.Add(new Point2D(0, 10));
Console.WriteLine(points.ToString());
var newPoints = new Point2DList(points.FindAll((x) => x.X == 10));
Console.WriteLine(newPoints.ToString());
}
catch (Exception)
{
throw;
}
finally
{
Console.ReadLine();
}
}
}
public class Point2DList : List<Point2D>
{
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine("List of Points");
foreach (var pt in this)
{
sb.AppendLine(pt.ToString());
}
return sb.Remove(sb.Length - 1, 1).ToString();
}
public Point2DList()
{
}
public Point2DList(IEnumerable<Point2D> ls)
: base(ls)
{
}
}
public class Point2D
{
public int X { get; set; }
public int Y { get; set; }
public Point2D(int x, int y)
{
X = x;
Y = y;
}
public override string ToString()
{
return X + "," + Y;
}
}
}
https://dotnetfiddle.net/WJM1O1
I have trouble with figuring out how can I use generic types to solve my problem.
Also I don't know how to describe my problem in short so I will make simplified version of my problem as extended exmplanation.
I am making system for switching quality, transitioning quality levels between different types of 'component' class.
I have base class like:
public abstract class QualityLevel_Base
{
public bool Enabled = true;
public virtual void Transition(QualityLevel_Base a, QualityLevel_Base b, double value)
{
if (value >= 1) Enabled = b.Enabled; else if (value <= 0) Enabled = a.Enabled;
}
protected static double Lerp(double a, double b, double t) { return (1 - t) * a + t * b; }
}
Then I inherit from it like:
public sealed class QualityLevel_LightSource : QualityLevel_Base
{
public double Intensity;
public double Range;
public int ShadowsQuality;
public override void Transition(QualityLevel_Base a, QualityLevel_Base b, double value)
{
QualityLevel_LightSource la = a as QualityLevel_LightSource; // One part of my problem - avoid casting
QualityLevel_LightSource lb = b as QualityLevel_LightSource;
base.Transition(a, b, value);
Intensity = Lerp(la.Intensity, lb.Intensity, value);
/* etc... */
}
}
Then I want to manage quality levels in other class and be able to apply settings onto desired component class.
So I have base class to manage any count of quality levels:
public abstract class QualityManager_Base
{
public Component SourceComponent { get; protected set; }
public List<QualityLevel_Base> QualityLevels { get; protected set; }
public virtual void Initialize(Component component, int qualityLevelsCount)
{
QualityLevels = new List<QualityLevel_Base>();
SourceComponent = component;
AutoQualitySettings(qualityLevelsCount);
}
public virtual void AutoQualitySettings(int qualityLevelsCount) { }
public virtual void ApplyQualitySettings(QualityLevel_Base qualityLevel)
{
SourceComponent.Enabled = qualityLevel.Enabled;
}
}
And I inheriting it for LightSource like:
public sealed class QualityManager_LightSource : QualityManager_Base
{
public LightSource Light { get; private set; }
public override void Initialize(Component component, int qualityLevelsCount)
{
LightSource light = component as LightSource; // Another situation when I would like to avoid casting
Light = light;
base.Initialize(light, qualityLevelsCount);
}
public override void AutoQualitySettings(int qualityLevelsCount)
{
for (int i = 0; i < qualityLevelsCount; i++)
{
QualityLevel_LightSource lightSettings = new QualityLevel_LightSource();
lightSettings.Intensity = Light.Intensity;
lightSettings.Range = Light.Range;
lightSettings.ShadowsQuality = i / qualityLevelsCount;
if (i == qualityLevelsCount - 1) lightSettings.Enabled = false;
}
}
public override void ApplyQualitySettings(QualityLevel_Base qualityLevel)
{
base.ApplyQualitySettings(qualityLevel);
// To my Question: I want to use generic type to avoid casting
QualityLevel_LightSource lightSettings = qualityLevel as QualityLevel_LightSource;
Light.Intensity = lightSettings.Intensity;
Light.Range = lightSettings.Range;
Light.ShadowsQuality = lightSettings.ShadowsQuality;
}
}
Actually I managed to use generic types on this problem making stuff like:
public abstract class QualityLevel_Base<T> where T : QualityLevel_Base<T> { /*...*/ }
public class QualityLevel_LightSource : QualityLevel_Base<QualityLevel_LightSource> { /*...*/ }
public abstract class QualityManager_Base
{
public List<QualityLevel_Base> QualityLevels; // Would like to define it like that but I have to do it
// like that:
public abstract class QualityManager_Base<T> where T : QualityLevel_Base<T>
{
public List<QualityLevel_Base<T>> QualityLevels;
}
Then doing something like this causes error:
public abstract class QualityManager_Base<T> where T : QualityLevel_Base<T>
{
public List<QualityLevel_Base<T>> QualityLevels;
public virtual void AddComponentForQualityManager(Component comp)
{
if (QualityLevels == null) QualityLevels = new List<QualityLevel_Base<T>>();
LightSource light = comp as LightSource;
if (light != null)
{
QualityManager_LightSource lightManager = new QualityManager_LightSource();
QualityLevels.Add(lightManager); // Then I Can't do this because: "cannot convert from 'QualityManager_LightSource' to 'QualityLevel_Base<T>' "
}
/* ... */
}
}
"cannot convert from 'QualityManager_LightSource' to 'QualityLevel_Base'"
There is of course more going on in my system, it is just very simplified version to define my question: How can I avoid casting classes, how can I do it correctly?
Thanks!
I am trying to build a unit test.
The class Position is implemented in a third party library. But for my unit test I need the Size property to be set to a specific value.
public class Position
{
private double _size;
private double Size
{
get
{
return _size;
}
internal set
{
_size = value;
}
}
}
I read this post: How do you create a unit-testing stub for an interface containing a read-only member?
but could not figure out how to make it work for me.
This is the class under test (just a simplified example). The posargument in the CalcPositionMetric() method must be of type Position:
public class PositionMetrics
{
public PositionMetrics()
{}
public double CalcPositionMetric(Position pos)
{
return 2 * pos.Size;
}
}
Here is a piece of my unit test:
using NUnit.Framework;
using NMock;
[TestFixture]
public class PositionUnitTests
{
[Test]
public void TestPosition()
{
Mock<Position> tmpPosMock = mFactory.CreateMock<Position>();
tmpPosMock.Expects.One.GetProperty(v => v.Size).WillReturn(7); /* !!! Exception !!! System.ArgumentException : mock object position has a getter for property Size, but it is not virtual or abstract */
/* Execute Test with tmpPositions*/
PositionMetrics pm = new PositionMetrics();
double result = pm.CalcPositionMetric(tmpPosMock.MockObject)
Assert.AreEqual(14, result);
}
}
But as you can see I get an exception. Could somebody help me to resolve this problem? Any other solutions are also welcome!
Cheers
Konstantin
New answer for the updated question I suggest you to introduce some kind of a proxy interface for that. See the code below:
interface IPosition {
int Size { get; }
}
class Position { //in 3rd party lib
public int Size {
get { return 5; }
}
}
class RealPosition : IPosition { //use this as your real object instead of using Position directly
private Position position;
public RealPosition(Position position) {
this.position = position;
}
public int Size {
get { return position.Size; }
}
}
class MockPosition : IPosition { //use this for testing
public int Size{ get; set; }
}
public class Program {
static void Main(string[] args) {
var pos = new MockPosition { Size = 7 };
Console.WriteLine(Calc(pos)); //prints 14
Console.ReadLine();
}
static int Calc(IPosition pos) { //change your method signature to work with interface
return pos.Size * 2;
}
}
Old answer If the class is not sealed you don't need any mocking libraries. Just use the new modifier for the required properties like this:
class Position {
public int Size { get { return 5; } }
}
class MockPosition : Position {
public new int Size { get; set; }
}
....
var mock= new MockPosition();
mock.Size = 7;
To use these items in some sort of list you'll have to cast them like this:
var items = new List<Position>();
for (int i = 0; i < 5; i++) {
items.Add(new MockPosition { Size = i });
}
foreach (var item in items.Cast<MockPosition>()) {
Console.Write("{0}\t", item.Size); //prints 0 1 2 3 4
}
If it is sealed and the property is not virtual than you'll have to use some other techniques, Moq (which I guess you are using) does not allow that
For example, I have a static class that contain all default methods. What if I want to generate a properties and simultaneously generate a default static method---
static class Default
{
//Auto-Generated
static int DEFAULT_foo1()
{
//Do something
}
static float DEFAULT_var2
{
//Do something
}
}
class Other
{
//Code-Snippet
int var1
{
get
{
return Default.DEFAULT_var1();
}
}
float var2
{
get
{
return Default.DEFAULT_var2();
}
}
}
I think standard inheritance be a good solution.
class OtherBase
{
//Code-Snippet
int var1
{
get
{
return Default.DEFAULT_var1();
}
}
float var2
{
get
{
return Default.DEFAULT_var2();
}
}
}
Derived class:
class Other : OtherBase
{
}
Change the class Default to be a singleton instead of being static. Now you can implement the method as well as the property in the same class with a code snippet. Other classes can derive from Default and inherit the properties automatically.
class Default
{
public static readonly Default Instance = new Default();
protected Default ()
{
}
public static int DoFoo1()
{
//Do something
}
public int Foo1 { get { return DoFoo1(); } }
public static float DoVar2
{
//Do something
}
public float Var2 { get { return DoVar2(); } }
}
class Other : Default
{
// Inherits Foo1 and Var2 automatically
}
Use of Default and Other
int x = Default.DoFoo1();
int y = Default.Instance.Foo1;
Other other = new Other();
int z = other.Foo1;
****Just below is my winform client inst with one parameter constructor within the class.****
private void button1_Click(object sender, EventArgs e)
{
string s1 = textBox1.Text;
int x1 = Convert.ToInt32(s1);
int X= x1;
ExternalTest ob = new ExternalTest(X);
string s2 = Convert.ToString(ob.Y);
ob.Y = 0;
textBox2.Text = s2;
And below this is my class that i added to the project
The code below is an added class within the assembly. If i tried to make it a class library and and add addreference - it will not build.
class ExternalTest
{
private int _x;
// protected new int x
// {
// get { return _x; }
// set {_x = value ;}
// }
private int y;
public int Y
{
get {return y = Mult(_x); }
set { }
}
internal int Mult(int _x)
{
y = _x + 51;
return y;
}
public ExternalTest(int X)
{
_x = X;
}
}
}
Your class is not public by default. You must add public to the definition of the class when you're using it in an external library, or the WinForms client will not be able to see it.
EG:
public class ExternalObj
{
// ...
}
Based on the fact that you are getting a compile error only when this class is in an external library, and the numerous times I've forgotten to add public when I've needed it myself, I'm thinking this is probably the issue.