I'm trying to make properties for mutable objects. Is this a problem with Auto-properties? For example, the following code would allow for unwanted manipulation of the mutable object. How would I avoid this?
public class Mutable{
public int Value { get; set; }
}
public class ClassWithMutable{
public Mutable Object { get; }
public ClassWithMutable(){
this.mutable = new Mutable();
this.mutable.Value = 0;
}
}
public class Demo{
public static void Main(String[] args){
ClassWithMutable test = new ClassWithMutable();
Mutable o = test.Object;
o.Value = 1;
}
}
You could use an interface that only exposes the get of the properties, and a private class that implements it.
public interface IImmutable {
int Value { get; }
}
public class ClassWithImmutable{
private Mutable _object;
public IImmutable Object { get { return _object; } }
public ClassWithImmutable(){
this._object = new Mutable();
this._object.Value = 0;
}
private class Mutable : IImmutable {
public int Value { get; set; }
}
}
public class Demo{
public static void Main(String[] args){
ClassWithImmutable test = new ClassWithImmutable();
IImmutable o = test.Object;
o.Value = 1; // fails
}
}
I'm trying to understand the intent of your question rather than your question, and I'm coming up a little short. However, I think I came up with something.
You can "mask" your mutable object under a read-only interface.
public class ClassWithMutable
{
public IImumutable Mutable { get { return _mutable; } }
private Mutable _mutable;
public ClassWithMutable()
{
_mutable = new Mutable()
{
Value = 1
};
}
}
public interface IImumutable
{
int Value { get; }
}
public class Mutable : IImumutable
{
public int Value { get; set; }
}
As long as your ClassWithMutable instance exposes the Mutable instance as an Immutable then the consumer can't easily change it. (I emphasize easily, because there's pretty much always a way that you can change it. It just depends on how hard you want to work.)
Related
I need to instantiate a list-property where the generic type can be anything.
So my Main-method looks like this: (In real, ParsingObject<T> are objects I get from a service)
public static void Main()
{
Parser parser = new Parser();
parser.AddAnObject(
new ParsingObject<int>{PropertyName = "FirstProperty", Active=true, DefaultValue=1}
);
parser.AddAnObject(
new ParsingObject<bool>{PropertyName = "SecondProperty", Active=false, DefaultValue=false}
);
parser.Parse();
}
ParsingObject gets any type (I think only string, bool, int,...) as generic. Now in my parser I need to add this object into a List<ParsingObject<T>> like:
public class Parser
{
private readonly List<ParsingObject<T>> _listOfObjects = new List<ParsingObject<T>>();
public void AddAnObject<T>(ParsingObject<T> item)
{
_listOfObjects.Add(item);
}
public void Parse()
{
foreach(var item in _listOfObjects.Where(w=>Active))
{
DoSomething(item);
}
}
}
but I know, I cannot set T as generic argument when instantiating the list (compiler is crying..).
So I could solve this with using ArrayList - but then I can't access the properties of each object. (See the Parse()-method)
for completeness, here is my ParsingObject<T>-class:
public class ParsingObject<T>
{
public string PropertyName { get; set; }
public bool Active { get; set; }
public T DefaultValue { get; set; }
}
Any idea how I could solve this? I cannot modify the ParsingObject<T>-class.
Depending on what exactly is your end goal, maybe something like this would be sufficient:
public class ParsingObjectBase
{
public string PropertyName { get; set; }
public bool Active { get; set; }
public Type ValueType { get; protected set; }
public object DefVal { get; protected set; }
}
public class ParsingObject<T> : ParsingObjectBase
{
public object DefaultValue
{
get { return (T)DefVal; }
set { DefVal = value; }
}
public ParsingObject()
{
ValueType = typeof(T);
}
}
private readonly List<ParsingObjectBase> _listOfObjects = new List<ParsingObjectBase>();
public void AddAnObject<T>(ParsingObject<T> item)
{
_listOfObjects.Add(item);
}
public void Parse()
{
foreach(var item in _listOfObjects.Where(w=>w.Active))
{
DoSomething(item); //do what exactly?
}
}
You obviously can't do without casting either to concrete ParsingObject<T> or DefVal value in this case, but you have Type information stored in one place and have access to your specific properties. Maybe changing ValueType to some kind of enum would be easier to use with switch?
i'm trying to minimize use of constractors in derived classes, and have a base class to hold common properties
so i tried as follows
public class sharedData
{
public string GlobMeta;
public int GlobValue;
public sharedData(string meta, int value)
{
GlobMeta = meta;
GlobValue= value;
}
}
public class derivedData: sharedData
{
public string test;
test = string.Format("Shared meta = {0}, Shared Value = {1}",GlobMeta, GlobValue);
}
then use
var shared = new sharedData("desc", 1);
var derived = new derivedData();
var testData = derived.test;
so when i will create instance of derived it will use base (shared) values
wich is common to all derived classes.
how can i implement this, as my idea was to use less memory with large collections of data. and also clean code and ease of use.
You have declared a based class, sharedData, without parameterless constructor. Therefore, any class that inherit that class must define a base constructor. You can't rely on the the compiler do job the job for you anymore.
public class derivedData : sharedData
{
public string test;
public derivedData(string meta, int value) : base(meta, value)
{
// you can't do assignment in the class scope, unless it can be done statically, it has to be inside a method block
test = string.Format("Shared meta = {0}, Shared Value = {1}", GlobMeta, GlobValue);
}
// or, if you prefer to have a parameterless ctor
public derivedData() : base("a default value for meta", default(int))
{
test = string.Format("Shared meta = {0}, Shared Value = {1}", GlobMeta, GlobValue);
}
}
EDIT: It seems that you are using this for global settings, in that case, you need to mark GlobMeta and GlobValue as static. Otherwise they won't be "shared" at all between different instance of sharedData/derivedData.
You should consider rewriting it as this :
public static class SharedData
{
public static string Meta { get; private set; }
public static int Value { get; private set; }
public static void SetData(string meta, int value)
{
Meta = meta;
Value = value;
}
}
public class DerivedData
{
public string Test
{
get { return string.Format("Shared meta = {0}, Shared Value = {1}", SharedData.Meta, SharedData.Value); }
}
}
EDIT 2 : If you need to have various instances of these, use the following :
public class SharedData
{
public string Meta { get; set; }
public int Value { get; set; }
public SharedData(string meta, int value)
{
Meta = meta;
Value = value;
}
}
public class DerivedData : SharedData
{
public string Test
{
get { return string.Format("Shared meta = {0}, Shared Value = {1}", Meta, Value); }
}
public DerivedData(string meta, int value) : base(meta, value)
{
}
// note: this is a copy ctor, changing data after this has been created, will not affect this.
public DerivedData(SharedData data) : base(data.Meta, data.Value)
{
}
}
I was thinking along the same lines as Xiaoy312, and wrote this while he was posting his second example:
public class SharedData
{
internal static string GlobMeta;
internal static int GlobValue;
public SharedData(string meta, int value)
{
GlobMeta = meta;
GlobValue = value;
}
public SharedData(){}
}
public class DerivedData: SharedData
{
public DerivedData() : base()
{
Console.WriteLine("Shared meta = {0}, Shared Value = {1}", GlobMeta, GlobValue);
}
}
Declaring the static variables as 'internal means they will only be accessible in the scope of 'SharedData and any classes derived from it.
I have 3 classes MetaA, MetaB and MetaC. Each have a number of properties.
There are certain situations where it would be nice to just have one class that contains the properties of all three Meta classes, called for example, MetaComposite. In the composite class, I have tried creating and instance of each MetaA, B and C in the hope that I could access the properties like so:
Meta Composite mc = new MetaComposite();
mc.MetaA.Property1 = "Hello";
Since C# does not allow multiple inheritance, what is the best way of making a class that is a composite of other classes? I could put fields and write getters and setters in the composite class to pass on the property values, but this would be a lot of duplicated code.
What is the correct approach here?
How about creating interfaces for all three Meta classes and have the MetaComposite class implement all three of these interfaces. The MetaComposite class can instantiated the correct Meta class and call it to execute the desired property.
Here is an example:
public interface IMeta1
{
int Metaproperty1 {get; set;}
}
public interface IMeta2
{
int Metaproperty2 {get; set;}
}
public interface IMeta3
{
int Metaproperty3 {get; set;}
}
public class MetaComposite : IMeta1, IMeta2, IMeta3
{
private readonly Meta1 _meta1;
private readonly Meta2 _meta2;
private readonly Meta3 _meta3;
public MetaComposite()
{
_meta1 = new Meta1();
_meta2 = new Meta2();
_meta3 = new Meta3();
}
public int Property1
{
get { return _meta1.Property1; }
set { _meta1.Property1 = value; }
}
public int Property2
{
get { return _meta2.Property2; }
set { _meta2.Property2 = value; }
}
public int Property3
{
get { return _meta3.Property3; }
set { _meta3.Property3 = value; }
}
}
What is the reason to have all properties on class level?
Why not simply use exactly what you wrote?
class MetaComposite
{
public MetaAClass MetaA { get; private set; }
public MetaBClass MetaB { get; private set; }
public MetaCClass MetaC { get; private set; }
public MetaComposite()
{
MetaA = new MetaAClass();
MetaB = new MetaBClass();
MetaC = new MetaCClass();
}
}
public void Main()
{
var composite = new MetaComposite();
composite.MetaA.Field1 = 1;
composite.MetaB.Field2 = '2';
composite.MetaC.Field3 = new MetaDClass();
}
I often end up writing classes like this:
public class Animal
{
public string Colour { get; set; }
public int Weight { get; set; }
public Animal(Dog data)
{
this.Colour = data.Colour;
this.Weight = data.Weight;
}
public Animal(Cat data)
{
this.Colour = data.Colour;
this.Weight = data.Weight;
}
}
When you have lots of properties and types then you quickly end up with a lot of boiler plate code. Ideally in this situation I would just create an IAnimal interface and reference that. I'm currently in a situation where the Dog and Cat classes exist in a third party assembly and I can't modify them. The only solution that I can come up with is:
public class Animal
{
public string Colour { get; set; }
public int Weight { get; set; }
public Animal(Cat data){Init(data);}
public Animal(Dog data){Init(data);}
private void Init(dynamic data)
{
this.Colour = data.Colour;
this.Weight = data.Weight;
}
}
This works but I lose all type safety, is there a better solution than constructor injection?
Thanks,
Joe
EDIT: Here is a real world example. I have a third party library which returns 3 objects called:
GetPageByIdResult
GetPagesByParentIdResult
GetPagesByDateResult
(These are all auto generated classes from a service reference and the properties are pretty much identical)
Instead of dealing with these three objects I want to deal with a single PageData object or a collection of them.
You can have the logic in one common constructor that all the other constructors call:
public class Animal
{
public string Colour { get; set; }
public int Weight { get; set; }
public Animal(Dog data) : this (data.Colour, data.Weight)
{
}
public Animal(Cat data) : this (data.Colour, data.Weight)
{
}
private Animal(string colour, int weight)
{
this.Colour = colour;
this.Weight = weight;
}
}
This is pretty similar to your second solution but it doesn't lose type safety.
I'm currently in a situation where the Dog and Cat classes exist in a
third party assembly and I can't modify them
I'd suggest Automapper-based solution:
public static class AnimalFactory
{
public static Animal Create<T>(T source)
where T : class
{
Mapper.CreateMap<T, Animal>();
return Mapper.Map<Animal>(source);
}
}
Usage:
var catAnimal = AnimalFactory.Create(cat);
var dogAnimal = AnimalFactory.Create(dog);
Of course, you can provide a way to custom mapping configuration, if needed.
If you do not want to have the class littered like that you can try Extension methods?
public static Animal ToAnimal(this Dog item)
{
return new Animal() {Weight = item.Weight, Colour = item.Colour};
}
public static Animal ToAnimal(this Cat item)
{
return new Animal() {Weight = item.Weight, Colour = item.Colour};
}
try using json serializer's, with that we can ensure type safety.
public class Animal
{
public string Colour { get; set; }
public long Weight { get; set; }
public string Name { get; set; }
public Animal Create<T>(T anyType)
{
return GetObject<T, Animal>(anyType);
}
public K GetObject<T, K>(T type1)
{
try
{
var serialized = JsonConvert.SerializeObject(type1);
return JsonConvert.DeserializeObject<K>(serialized);
}
catch (Exception ex)
{
return default(K);
}
}
}
class Program
{
public static void Main(string[] args)
{
Animal obj = new Animal();
var animal = obj.Create(new { Colour = "Red", Weight = 100 });
//here you can pass any object, only same name properties will be initialized..
Console.WriteLine(animal.Colour + " : " + animal.Weight);
Console.ReadKey();
}
}
I'm wondering about what's the way to go, if I need to publicate data-interfaces but want to use them internal with extended calculated properties. To make it clearer:
// The public interface
public interface IData
{
int Property { get; }
}
// The internal interface
internal interface IExtendedData : IData
{
int ExtendedProperty { get; }
}
// The assumed implementation of someone using my interface
public class Data : IData
{
public Data(int a)
{
Property = a;
}
public int Property
{
get;
private set;
}
public override string ToString()
{
return Property.ToString();
}
}
// My implementation
internal class ExtendedData : IExtendedData
{
public ExtendedData(int a)
{
Property = a;
}
public int Property
{
get;
private set;
}
public int ExtendedProperty
{
get
{
return 2 * Property;
}
}
public override string ToString()
{
return Property.ToString() + ExtendedProperty.ToString();
}
}
// publicated by me, for the person who uses my dll
public static class Calculations
{
public static int DoSomeCalculation(IData data, int parameter)
{
// This probably don't work, but maybe shows what I want to do
IExtendedData tempData = (ExtendedData)data;
return tempData.ExtendedProperty * parameter;
}
}
I'm realy frustrated, cause I feel like missing some basical programing skills.
You could solve this problem by implementing ExtendedData as a Wrapper for a class implementing IData
internal class ExtendedData : IExtendedData
{
private IData data;
public ExtendedData(IData data)
{
this.data = data;
}
public int Property
{
get { return data.Property; }
private set { data.Property = value; }
}
public int ExtendedProperty
{
get
{
return 2 * Property;
}
}
}
and use this in DoSomeCalculation like
IExtendedData tempData = new ExtendedData(data);
ExtendedData could inherit from Data:
class ExtendedData : Data
{...}
And for creation of a Data object you add a factory like so:
public class DataFactory
{
public IData CreateData()
{
return new ExtendedData();
}
}
User have to create all its Data objects by this factory. You can ensure it by making Data's constructor internal.
In your DLL you can then cast to ExtendedData.