I wanted to know what is a good option to solve this issue ,
I have a class that expose an enum : (this is just an example)
public class Foo
{
public State FooState { get; private set; }
public string SomeData { get; set; }
public Foo(State state)
{
FooState = state;
}
public Foo()
{
}
public enum State
{
None,
Bad,
Good
}
}
in one use of the class the user can adjust the state, and on the other he can't so the state is set on NONE and that good but i dont want the user to have the possibility of setting it to None. i Know that there isnt an internal enum field obviously, is there any way it can be done else, bare in mine that the Foo class cant be changed due to specification.
Clarification
The meaning of the class can not be change is that the design and purpose of the class can not change, not the class itself.
The state of the class is only in use when the c'tor get a value. i cant use two classes or use interface due to reflection use in the future. (i just cant use typeof)
I believe you can do this by providing two interfaces with different access level, implement them explicitly and instead of Foo type use one of the interfaces either for read-only or full access.
Since Foo can not be changed you can use Wrapper approach:
Foo foo = new Foo(State.Good);
FooWrapper fooWrapper = new FooWrapper(foo);
// would be read-write
(FooWrapper as IReaonlyState).State
// would be readonly
(FooWrapper as IWritableState).State
public interface IReadonlyState
{
State FooState { get; }
}
public interface IWritableState
{
State FooState { get; set; }
}
public class FooWrapper : IReadonlyState, IWritableState
{
Foo foo;
public FooWrapper(Foo foo)
{
this.foo = foo;
}
State IReadonlyState.FooState
{
get
{
return this.foo.FooState;
}
}
State IWritableState.FooState
{
get
{
return this.foo.FooState;
}
set
{
this.foo.FooState = value;
}
}
}
So, you want the consumer to be able to set both State=Bad and State=Good.
But if State==None you should be able to read, but not change it. Sounds like you need to implement the setter explicitly.
Related
I'm writing a little game, and the game has a State class to keep track of game state. The State class is only intended to be modifiable by Commands (command pattern). The State class includes lists of other classes - e.g. a Faction class, which contains members like resources, a list of owned Units, etc.
How can I make the deep innards of State readable from other classes, without also leaking writable references inside of State itself?
Currently, I have specialized getters like State.GetOwnerOfUnitAtLocation(x), which only return safe values (int factionid etc.), but I am beginning to need a lot of these, and the class is getting really unwieldy. I would prefer to have those methods in more appropriate locations (Map.Units.GetOwner(x) or something), but I don't know how to expose the internals of State to other classes in a safe way.
Relatedly, Command is an interface that currently lives inside of the State class, along with all the actual commands that implement it, so that it can modify private members of State. Is there a better way to implement this?
Edit: A selection of code from State to illustrate the first issue:
public partial class State
{
public int Turn {get; private set;} = 1;
private Dictionary<Vector2, FactionsMgr.Faction> _unit_map = new Dictionary<Vector2, FactionsMgr.Faction>();
public int GetUnitRemainingMobility(Vector2 pos)
{
if (IsUnitAt(pos))
{
FactionsMgr.Faction owner = _unit_map[pos];
int taken_movement = owner.units[pos]._taken_movement;
int max_mobility = UnitsMgr.GetMaxMobility(owner.units[pos].type);
return max_mobility - taken_movement;
}
else
{
GD.Print("Warning: GetUnitRemainingMobility asked for unknown unit: ", pos);
return -1;
}
}
}
Since FactionsMgr.Faction is mutable, let's suppose that it has writable properties like this:
class Faction {
public int Foo { get; set; }
public string Bar { get; set; }
public float Baz { get; set; }
public SomeOtherMutableThing AnotherThing { get; set; }
}
You should create a corresponding read only interface for it, and make Faction implement it:
interface IReadOnlyFaction {
// exclude all members that can change Faction's state
int Foo { get; }
string Bar { get; }
float Baz { get; }
IReadOnlySomeOtherMutableThing AnotherThing { get; }
}
interface IReadOnlySomeOtherMutableThing {
// do the same thing there...
}
class Faction: IReadOnlyFaction {
public int Foo { get; set; }
public string Bar { get; set; }
public float Baz { get; set; }
public SomeOtherMutableThing AnotherThing { get; set; }
// you need an explicit interface implementation here, unless you are using C# 9
IReadOnlySomeOtherMutableThing IReadOnlyFaction.AnotherThing => AnotherThing;
}
Then, you can declare public members in State as of type IReadOnlyFaction, and delegate them to a private member of type Faction. The private member is also what the Command class will modify.
private Faction someFaction;
public IReadOnlyFaction SomeFaction => someFaction;
That is the general case. However, if you have collections of these mutable types, like your dictionary of _unit_map, you would need to do a bit more work.
You would still have a public read only member and a private mutable member, but the delegating process is less straightforward. You would need a wrapper.
private Dictionary<Vector2, FactionsMgr.Faction> _unit_map = new();
public IReadOnlyDictionary<Vector2, IReadOnlyFaction> UnitMap;
// ...
// in the constructor of State...
// using the ReadOnlyDictionaryWrapper class from the linked answer
UnitMap = new ReadOnlyDictionaryWrapper<Vector2, FactionsMgr.Faction, IReadOnlyFaction>(_unit_map);
Is it possible to have a class with unknown amount or types of properties, that will restrict the property access if needed, in runtime.
For example, if we have the following class:
public class SomeClass
{
public string SomeProperty { get; set; }
}
Then, accessing the class property outcome will depend on some runtime state, that is controllable by classes that are aggregated to it in some way.
A possible solution, would be to add some public boolean variable that can be set, then determain the behaviour by it.
For example:
public class SomeClass
{
public bool CanAccess { get; set; }
private string _someProperty;
public string SomeProperty
{
get
{
if (CanAccess)
{
return _someProperty;
}
throw new Exception();
}
set
{
if (CanAccess)
{
_someProperty = value;
}
throw new Exception();
}
}
}
This solution however, will require the class implementor to:
Do it right
Do it for all properties
I am not sure it is possible, but I want to implement that class in some way that will eliminate the need to check this "CanAccess" feild for every property.
This further means that if in the future I add some more properties to that class, they will also comply that "CanAccess" state automatically.
Thanks for helping.
I used to be able to do this:
public class Something
{
public class SomethingElse
{
public static class ThisThing
{
public static string aoidj {get;set;}
}
}
}
But it no longer works.
My desired result (and what I've always been able to do) is:
Something.SomethingElse somethingElse = new Something.SomethingElse();
somethingElse.ThisThing.aoidj = "yay";
Console.WriteLine(somethingElse.ThisThing.aoidj);
But that no longer works. Instead of being able to access ThisThing from somethingElse, it's now appearing in SomethingElse.!
Has the C# language changed or something? The behaviour is definitely different and I don't know when it changed.
You need to do this:
Something.SomethingElse.ThisThing.aoidj = "yay";
Console.WriteLine(Something.SomethingElse.ThisThing.aoidj);
Or otherwise change your code to this:
public class Something
{
public class SomethingElse
{
public Whatever ThisThing = new Whatever();
public class Whatever
{
public string aoidj {get;set;}
}
}
}
And then you could do this (your desired result):
Something.SomethingElse somethingElse = new Something.SomethingElse();
somethingElse.ThisThing.aoidj = "yay";
Console.WriteLine(somethingElse.ThisThing.aoidj);
It has to appear in the SomethingElse., otherwise, how can you acces it, it is a Nested Type!
C# has not changed in this way. Nested Types have always been accessible through their parent types.
See my answer here: Cannot access nested classes or members of base class.
Besides, there is no point in having static classes as a Nested Type, since static classes are more commonly used as managers or providers, so they are mainly used elsewhere in your system.
Aside, if you want to access your static class members, you have to type in its name and access it once and for all.
Something.SomethingElse.ThisThing.aoidj
But I can't do that. It would be bad. I need to do it from somethingElse. Not SomethingElse.
Than make it a property rather than a class.
public class Something {
public class SomethingElse {
public OrEventSomethingElse ThisThing { get; set; }
}
}
public class OrEventSomethingElse {
public string aoidj { get; set; }
}
This way, you shall not be able to access it through your Nested Type SomethingElse, but rather through only an instance.
Some resources to help you understand OOP.
Object-Oriented Programming (C# and Visual Basic)
C# Tutorial - An Object Oriented Approach to Programming
Introduction to C# classes
C#.Net Tutorial 17-1 - Classes and Object-Oriented Programming (Part 1)
.NET Tutorial : Object Oriented Programming Using C# For Beginners - Part 1 - Introduction
Beginning C# Object-Oriented Programming
Object Oriented Programming using C# (DOWNLOAD FREE)
** I need it to be a class though, because there is more stuff to go inside of ThisThing**
Make it a class outside of SomethingElse so that you may access it as a simple instance member/property.
public class ThisThing {
public string Stuff { get; set; }
public int SomeMoreStuff { get; set; }
public DateTime EvenMoreStuff { get; set; }
// ...
public string ThisClassIsGettingHuge {
get {
return "Time to refactor because big classes tend to break SRP";
}
}
}
public class Something {
public class SomethingElse {
public ThisThing ThisThingAsAProperty { get; set; }
}
}
It is then, and only then that you shall only be able to access your instance.
var somethingElse = new Something.SomethingElse;
Console.WriteLine(somethingElse.ThisThingAsAProperty.ThisClassIsGettingHuge);
I have developed information and process for years, and I rarely use Nested Types. They generally cause more damage than they help.
Nothing is changed, but your code is wrong. And luckily I found answer too.
class Something
{
public class SomethingElse
{
public SomethingElse()
{
}
public static class sm
{
public static void set()
{
}
}
}
}
Use the class in this manner-
Something.SomethingElse.sm.set();
I want to show MyProperty1 or MyProperty2 based on MyPropertySelected. How to use a conditional statement if or else based on MyPropertySelected? Thanks.
// [Browsable(true)
// ????? conditional statement IF ELSE in here..
// IF (MyPropertySelected) MyProperty1 will be show ELSE MyProperty2 will be show.
public bool MyPropertySelected { get; set; }
// [Browsable(true) or [Browsable(false) depending on MyPropertySelected condition.
public int MyProperty1 { get; set; }
// [Browsable(true) or [Browsable(false) depending on MyPropertySelected condition.
public int MyProperty2 { get; set; }
You're confusing apples with oranges.
Attributes are metadata and a property value acquires its value on run-time.
In other words: attribute is something that you'll access using reflection and those aren't tied to a particular object but to the type of the object (i.e. the class).
Another issue is that you want to add an attribute to a property based on a condition that can't work in compile-time.
Your MyPropertySelected won't get any value until its enclosing class gets instantiated - that's creating an object, for example: MyClass a = new MyClass()-, meaning that adding or not adding the attribute would never be a compile-time choice.
I want to be clear: you can't do what you want purely using attributes!
You can't conditionally apply attributes based on run-time values.
Finally, I suspect you want to make something Browsable based on a condition, like your own question says. You can't do that.
Ok ok, but what...?
You can workaround your situation with a different software design.
1)
First, create an interface that will have any of the properties that would be browsable or not. But don't apply the attribute [Browsable(bool)] to the interface properties.
2)
Create two classes that implements the previously created interface.
In the first class, implement the interface properties and put a [Browsable(true)] attribute on them. In the second class, do the same, but this time put a [Browsable(false)] on them.
3)
Some code that creates the instance of the object will be the one that will also decide which one will be instantiated.
That is, externalizing MyPropertySelected outside of both classes and performing the whole condition switch in the caller.
public interface IBrowsableProperties
{
int Property1 { get;set; }
int Property2 { get;set; }
}
public class A : IBrowsableProperties
{
[Browsable(true)]
public int Property1 { get;set; }
[Browsable(true)]
public int Property1 { get;set; }
}
public class B : IBrowsableProperties
{
[Browsable(false)]
public int Property1 { get;set; }
[Browsable(false)]
public int Property1 { get;set; }
}
// Somewhere in some method...
bool propertySelected = true;
IBrowsableProperties instance = null;
if(propertySelected)
{
instance = new A();
}
else
{
instance = new B();
}
// ... do stuff with your instance of IBrowsableProperties!
UPDATE
I've reviewed some of your question's comments and I've found you're working with PropertyGrid control.
Anyway, you can apply the concept in your case. PropertyGrid can be inherited. You can create both PropertyGrid1 and PropertyGrid2 derived classes that both implement the proposed interface!
You probably want an intermediary property like this:
class Foo
{
public bool MyPropertySelected
{
get;
set;
}
public readonly int MyProperty
{
get
{
return MyPropertySelected ? MyProperty1 : MyProperty2;
}
}
private int MyProperty1
{
get;
set;
}
private int MyProperty2
{
get;
set;
}
}
I have a project where I need to construct a fair amount of configuration data before I can execute a process. During the configuration stage, it's very convenient to have the data as mutable. However, once configuration has been completed, I'd like to pass an immutable view of that data to the functional process, as that process will rely on configuration immutability for many of its computations (for instance, the ability to pre-compute things based on initial configuration.) I've come up with a possible solution using interfaces to expose a read-only view, but I'd like to know if anybody has encountered problems with this type of approach or if there are other recommendations for how to solve this problem.
One example of the pattern I'm currently using:
public interface IConfiguration
{
string Version { get; }
string VersionTag { get; }
IEnumerable<IDeviceDescriptor> Devices { get; }
IEnumerable<ICommandDescriptor> Commands { get; }
}
[DataContract]
public sealed class Configuration : IConfiguration
{
[DataMember]
public string Version { get; set; }
[DataMember]
public string VersionTag { get; set; }
[DataMember]
public List<DeviceDescriptor> Devices { get; private set; }
[DataMember]
public List<CommandDescriptor> Commands { get; private set; }
IEnumerable<IDeviceDescriptor> IConfiguration.Devices
{
get { return Devices.Cast<IDeviceDescriptor>(); }
}
IEnumerable<ICommandDescriptor> IConfiguration.Commands
{
get { return Commands.Cast<ICommandDescriptor>(); }
}
public Configuration()
{
Devices = new List<DeviceDescriptor>();
Commands = new List<CommandDescriptor>();
}
}
EDIT
Based on input from Mr. Lippert and cdhowie, I put together the following (removed some properties to simplify):
[DataContract]
public sealed class Configuration
{
private const string InstanceFrozen = "Instance is frozen";
private Data _data = new Data();
private bool _frozen;
[DataMember]
public string Version
{
get { return _data.Version; }
set
{
if (_frozen) throw new InvalidOperationException(InstanceFrozen);
_data.Version = value;
}
}
[DataMember]
public IList<DeviceDescriptor> Devices
{
get { return _data.Devices; }
private set { _data.Devices.AddRange(value); }
}
public IConfiguration Freeze()
{
if (!_frozen)
{
_frozen = true;
_data.Devices.Freeze();
foreach (var device in _data.Devices)
device.Freeze();
}
return _data;
}
[OnDeserializing]
private void OnDeserializing(StreamingContext context)
{
_data = new Data();
}
private sealed class Data : IConfiguration
{
private readonly FreezableList<DeviceDescriptor> _devices = new FreezableList<DeviceDescriptor>();
public string Version { get; set; }
public FreezableList<DeviceDescriptor> Devices
{
get { return _devices; }
}
IEnumerable<IDeviceDescriptor> IConfiguration.Devices
{
get { return _devices.Select(d => d.Freeze()); }
}
}
}
FreezableList<T> is, as you would expect, a freezable implementation of IList<T>. This gains insulation benefits, at the cost of some additional complexity.
The approach you describe works great if the "client" (the consumer of the interface) and the "server" (the provider of the class) have a mutual agreement that:
the client will be polite and not try to take advantage of the implementation details of the server
the server will be polite and not mutate the object after the client has a reference to it.
If you do not have a good working relationship between the people writing the client and the people writing the server then things go pear-shaped quickly. A rude client can of course "cast away" the immutability by casting to the public Configuration type. A rude server can hand out an immutable view and then mutate the object when the client least expects it.
A nice approach is to prevent the client from ever seeing the mutable type:
public interface IReadOnly { ... }
public abstract class Frobber : IReadOnly
{
private Frobber() {}
public class sealed FrobBuilder
{
private bool valid = true;
private RealFrobber real = new RealFrobber();
public void Mutate(...) { if (!valid) throw ... }
public IReadOnly Complete { valid = false; return real; }
}
private sealed class RealFrobber : Frobber { ... }
}
Now if you want to create and mutate a Frobber, you can make a Frobber.FrobBuilder. When you're done your mutations, you call Complete and get a read-only interface. (And then the builder becomes invalid.) Since all the mutability implementation details are hidden in a private nested class, you can't "cast away" the IReadOnly interface to RealFrobber, only to Frobber, which has no public methods!
Nor can the hostile client create their own Frobber, because Frobber is abstract and has a private constructor. The only way to make a Frobber is via the builder.
This will work, but "malicious" methods may try to cast an IConfiguration to a Configuration and thereby bypass your interface-imposed restrictions. If you're not worried about that then your approach will work fine.
I usually do something like this:
public class Foo {
private bool frozen = false;
private string something;
public string Something {
get { return something; }
set {
if (frozen)
throw new InvalidOperationException("Object is frozen.");
// validate value
something = value;
}
}
public void Freeze() {
frozen = true;
}
}
Alternatively, you could deep-clone your mutable classes into immutable classes.
Why can't you provide a separate immutable view of the object?
public class ImmutableConfiguration {
private Configuration _config;
public ImmutableConfiguration(Configuration config) { _config = config; }
public string Version { get { return _config.Version; } }
}
or if you don't like the extra typing, make the set members internal rather than public - accessible within the assembly but not by clients of it?
I'm regularly working with a large, COM-based framework (ESRI's ArcGIS Engine) that handles modifications very similarly in some situations: there are the "default" IFoo interfaces for read-only access, and IFooEdit interfaces (where applicable) for modifications.
That framework is fairly well-known, and I'm not aware of any widespread complaints about this particular design decision behind it.
Finally, I think it's definitely worth some additional thought in deciding which "perspective" gets to be the default one: the read-only perspective or the full-access one. I would personally make the read-only view the default.
How about:
struct Readonly<T>
{
private T _value;
private bool _hasValue;
public T Value
{
get
{
if (!_hasValue)
throw new InvalidOperationException();
return _value;
}
set
{
if (_hasValue)
throw new InvalidOperationException();
_value = value;
}
}
}
[DataContract]
public sealed class Configuration
{
private Readonly<string> _version;
[DataMember]
public string Version
{
get { return _version.Value; }
set { _version.Value = value; }
}
}
I called it Readonly but I'm not sure that's the best name for it though.