In C#, can I hide/modify accessors in subclasses? - c#

I'm not even sure what this principle is called or how to search for it, so I sincerely apologize if it has been brought up before, but the best way to do it is with an example.
class Properties
{
public string Name { get; set; }
}
class MyClass
{
class SubProperties: Properties
{
public override Name
{
get { return GetActualName(); }
set { SetActualName(value); }
}
}
public SubProperties ClassProperties;
private string GetActualName()
{
return SomeFunction();
}
private void SetActualName(string s)
{
ClassProperties.Name = SomeOtherFunction(s);
}
}
The idea is to have any object that instantiates MyClass have a fully accessible property ClassProperties. To that object, it would look exactly like a Properties object, but behind the scenes, MyClass is actually computing and modifying the results of the fields. This method of declaration is obviously wrong since I can't access GetActualName() and SetActualName() from within the SubProperties definition. How would I achieve something like this?

Are you looking for something like this?
abstract class Properties
{
public abstract string Name { get; set; }
}
class MyClass
{
private class SubProperties : Properties
{
private MyClass myClass;
public SubProperties(MyClass myClass)
{
this.myClass = myClass;
}
public override Name
{
get { return this.myClass.GetActualName(); }
set { this.myClass.SetActualName(value); }
}
}
private string name;
public MyClass
{
this.MyClassProperties = new SubProperties(this);
}
public Properties MyClassProperties { get; private set; }
private string GetActualName()
{
return this.name;
}
private void SetActualName(string s)
{
this.name = s;
}
}
You need to pass a reference to a MyClass instance to the SubProperties instance if you want to access MyClass methods from SubProperties.

public virtual string Name { get; set; }

Related

ASP.NET WebService Only returns one field of my customized class

I'm using ASP.NET WebService(In C#),and have a WebMethod like this:
[WebMethod]
public Class1 GetClass1(string Param1)
{
return new Class1(Param1);
}
"Class1" is a customized Class with the following code:
public partial class Class1
{
public Class1() { }
public Class1(string Param1)
{
Prop1 = Param1;
}
}
public partial class Class1
{
public string Prop1
{
get
{
return _Prop1;
}
set
{
_Prop1 = value;
----Code to Update Other 2 Properties----
----One is Like Below----
_Prop2 = Get_Prop2_In_DataBase_By_Prop1(value);
}
}
private string _Prop1 = "0";
}
public partial class Class1
{
----Other 2 Properties----
}
Now I called GetClass1,but it only returns Prop1.I want it to show all the public fields in Class1.What's the problem?
---Edited at 2017-6-20 15:15:00---
My code defining the other two Properties are like following:
public string Prop2
{
get
{
return _Prop2;
}
}
private string _Prop2 = "0";
Solved.
The properties must have a setter to be serialized which is necessary to be shown by a WebService.
Thats why i asked you for the properties that you defined which was missed earlier.
public partial class Class1
{
public string prop2 { get; set; }
public string prop3 { get; set; }
}
As you mentioned you forgot setters !

Inheriting from an interface with properties of the same name

I have an interface IProduct and two partial classes SearchedProductInternal and SearchedProductExternal.
These two classes are extending classes coming from 3rd party webservice searches but both return slightly different result types.
I want to use the interface for both so they type returned is the same. I know how to inherit but what do I do to return the "Name" as both the interface and SearchedProductInternal have the same object name?
My Interface is similar to as follows:
public interface IProduct
{
string Name { get; }
string ID { get; }
string DescriptionShort { get; }
string DescriptionLong { get; }
}
My Object SearchedProductInternal has the following properties:
string Name;
int ObjectIdField;
string DescriptionShortField;
string DescriptionLongField;
So my this is where I am inheriting
public partial class SearchedProductInternal : IProduct
{
public string ID
{
get { return ObjectIdField.ToString(); }
}
public string Name
{
//What do I do here?
}
public string DescriptionShort{get { return shortDescriptionField; }
}
public string DescriptionLong {get { return longDescriptionField; }
}
}
I want to the return the name that has been originality assigned in the SearchedProductInternal class but I don't know how to do that because if I just put
return Name
I get a stackoverflow error as it appears to be just keeping calling its self?
I think what you should do here is to explicitly implement the interface, so that you will have both your Name property as defined in the class and the IProduct.Name property from your interface.
You can explicitly implement the interface, like so:
public partial class SearchedProductInternal : IProduct
{
string IProduct.ID
{
get { return ObjectIdField.ToString(); }
}
string IProduct.Name
{
get { return "Interface name"; }
}
string IProduct.DescriptionShort
{
get { return shortDescriptionField; }
}
string IProduct.DescriptionLong
{
get { return longDescriptionField; }
}
// Name property for the class, not the interface
public string Name
{
get { return "Class name"; }
}
}
This way you can differentiate between calls to your interface properties and properties with the same name on your class.
When accessing both properties you can also decide which you want, in the following manner:
var test = new SearchedProductInternal();
Console.WriteLine(test.Name); // returns "Class name"
Console.WriteLine((test as IProduct).Name); // returns "Interface name"
If your SearchedProductInternal already defines the property Name and you're trying to return the value of same Name property, you don't have to do anything.
Don't create one more property named Name. Just get rid of the Name property you added. Everything should work because the class already implemented the contract defined by the interface IProduct.
If you want to return different value from the IProduct.Name property, you can use explicit interface implementation.
You must change the name of the variable in this case Name.
If that was an ambigous sentence then remember it's the same for the PC. Name cannot be two things. but Name and _Name can.
public class SearchedProductInternal : IProduct
{
string _name = "test";
public string Name
{
get
{
return _name;
}
}
}
public interface IProduct
{
string Name { get; }
}
I agree with the above answer. But a minor issue here, we cannot expose the interface member as public, as it causes compile error.
We can have both class level and interface level members. The interface member cannot be accessed by using class instance, which can be accessed only through interface instance.
public interface IProduct
{
string Name { get; }
string ID { get; }
string DescriptionShort { get; }
string DescriptionLong { get; }
}
public partial class SearchedProductInternal : IProduct
{
private string _clsName;
private string _interfaceName;
private string _objectID;
private string _shortDesc;
private string _longDesc;
public SearchedProductInternal(string _cName, string _iName)
{
_clsName = _cName;
_interfaceName = _iName;
}
public string Name
{
get { return _clsName; }
}
string IProduct.Name
{
get { return _interfaceName; }
}
string IProduct.ID
{
get { return _objectID; }
}
string IProduct.DescriptionShort
{
get { return _shortDesc; }
}
string IProduct.DescriptionLong
{
get { return _longDesc; }
}
}
class Program
{
static void Main(string[] args)
{
SearchedProductInternal clsSearchProduct = new SearchedProductInternal("clsName", "interfaceName");
Console.WriteLine(clsSearchProduct.Name);
IProduct interfaceProduct = (IProduct)clsSearchProduct;
Console.WriteLine(interfaceProduct.Name);
Console.ReadLine();
}
}
I am not sure if I just explained this in a way that was not understood but the way that I got this to work was by just using {get;set;}
public partial class SearchedProductInternal : IProduct
{
public string ID
{
get { return ObjectIdField.ToString(); }
}
public string Name {get;set;}
public string DescriptionShort{get { return shortDescriptionField; }
}
public string DescriptionLong {get { return longDescriptionField; }
}
}

Set method parameters as readonly

how can i create a method that get's an object to read only purpose
public class Person
{
public string Name;
}
public void RunMe(Person p)
{
p.Name="XXXX";
}
var p =new Person();
p.Name="YYYY";
RunMe(p);
Console.WriteLine(p.Name);
I am getting XXXX. but i want that the person object will not change it value.
you can use interfaces to restrict the access. It is also better to pass interfaces instead of concrete objects as parameters to methods.
public interface IReadablePerson
{
string Name { get; }
}
public interface IWritablePerson
{
string Name { set; }
}
public class Person : IReadablePerson, IWritablePerson
{
public string Name { get; set; }
}
and then have a method like this
public void RunMe(IReadablePerson p)
{
p.Name = "XXXX"; //compile time error!!!
}
The way to do this is via the get and set accessors, just don't define a set:
public String Name { get; }
This will make a property that you can treat exactly like a normal field for your purposes. Underneath properties are a little more complex using methods to set a backing field which you can read about on msdn
If you need to be able to set the property just once then define the set as private and pass the parameter into the constructor:
public class Person
{
public Person(String name)
{
this.Name = name;
}
public String Name { get; private set; }
}
Classes in C# are reference types, so there's no way to do what you want to do if Person is a class.
You could make it a value type (by making it a struct) in which case, a copy of the object would be passed in, but that may take implications at some other points in your program, so be wary if you do it.
It seems that you want to somehow be able to lock the member. One option would be to make the "set" dependent on another member like this:
public class Name
{
public bool Locked { get; set; }
private string name;
public string Name
{
get { return this.name; }
set
{
if(!this.Locked)
this.name = val;
}
}
}
Edit: Alternate method for making lock permanent.
public class Person
{
private bool locked = false;
public void Lock()
{
this.locked = true;
}
public bool Locked
{
get { return this.locked; }
}
// add same Name member as above
}
Edit: Yet ANOTHER way to lock, using a key.
private object key = null;
public bool Locked
{ get { return this.key != null; } }
public void Lock(object obj)
{
if (this.key == null)
{
this.key = obj;
}
}
public void Unlock(object obj)
{
if (this.key == obj)
{
this.key = null;
}
}
You can throw an exception if you want if trying to unlock with the wrong key object.
The behaviour described after the first setting of the property is this:
private string _name;
public string Name
{
get { return _name; }
set { // no setting }
}
This is NOT A GOOD PRACTICE.
you create unexpected behaviour for properties (if this is a public class).
Any consuming assembly cannot view the body of the get and set methods would expect a set method to behave a sertain way (setting a value).
This kind of behaviour should be put in a seperate set method.
This way you can see if it changed, throw an exception if you want, or return true if it changed.
Then you can still use the property for getting the value.
private bool _locked;
public string Name { get; private set;}
public boolSetName(string value)
{
bool hasChanged = false;
if(!_locked)
{
Name = value;
_locked = true;
hasChanged = true;
}
return hasChanged
}

Trying to achieve additional scoping in C# Properties

I'm working on a utility that generates lots of C# classes. Most generated classes are small, but some get up to 50+ public members. I would like to be able to add an additional level of scoping just to reduce clutter and make them more IntelliSense-friendly.
For example, say I generate a class Foo with the following members:
Apple, Banana, Cantaloupe, Dog, Elephant, Fox, Geranium, Hibiscus, Iris.
Instead of IntelliSense showing all 9 members when I type new Foo()., I want to be able to scope the properties to categories. For example, new Foo().Animals. would list Dog, Elephant, and Fox.
The only way I can think of to do this is to create an inner class for each category and creating a property on the parent class that returns an instance of the child class. This doesn't seem very elegant and I'm not sure if it's a good use of nested classes.
public class Scope
{
public FruitProperties Fruit { get; private set; }
public AnimalProperties Animals { get; private set; }
public FlowerProperties Flowers { get; private set; }
public Scope()
{
Fruit = new FruitProperties();
Animals = new AnimalProperties();
Flowers = new FlowerProperties();
}
public class FruitProperties
{
public string Apple { get { return "Apple"; } }
public string Banana { get { return "Banana"; } }
public string Cantaloupe { get { return "Cantaloupe"; } }
}
public class AnimalProperties
{
public string Dog { get { return "Dog"; } }
public string Elephant { get { return "Elephant"; } }
public string Fox { get { return "Fox"; } }
}
public class FlowerProperties
{
public string Geranium { get { return "Geranium"; } }
public string Hibiscus { get { return "Hibiscus"; } }
public string Iris { get { return "Iris"; } }
}
}

Self-Referential Property array

I want to be able to loop through a Class Property that references its own properties. Why you may ask? Because it's easier to manage later on if I want to add more properties to that Class.
Let me explain more:
public interface IElementBox
{
string Filename { get; }
string FileDefinition { get; set; }
void ExtractFromFile(string stringData);
}
public abstract class Element
{
public Element(string stringData)
{
this.DefFromFile(stringData);
}
public string Name { get; set; }
protected abstract void DefFromFile(string stringData);
}
public class Solid : Element
{
public Solid(string stringData) : base(stringData) { }
public string SolidSpecificProperty { get; set; }
protected override void DefFromFile(string stringData)
{
// Assign SolidSpecificProperty from string
}
}
public class Liquid : Element
{
public Liquid(string stringData) : base(stringData) { }
public string LiquidSpecificProperty { get; set; }
protected override void DefFromFile(string stringData)
{
// Assign LiquidSpecificProperty from string
}
}
public class Gas : Element
{
public Gas(string stringData) : base(stringData) { }
public string GasSpecificProperty { get; set; }
protected override void DefFromFile(string stringData)
{
// Assign GasSpecificProperty from string
}
}
public abstract class ElementBox<T> : IElementBox where T : Element
{
public List<T> Elements { get; set; }
public List<T> GetElementsFromName(string name)
{
return this.Elements.FindAll(x => x.Name == name);
}
public abstract string Filename { get; }
public string FileDefinition { get; set; }
public abstract void ExtractFromFile(string filename);
}
public class SolidBox : ElementBox<Solid>
{
public override string Filename
{
get { return "Solid.txt"; }
}
public override void ExtractFromFile(string stringData)
{
this.Elements.Add(new Solid(stringData));
}
}
public class LiquidBox : ElementBox<Liquid>
{
public override string Filename
{
get { return "Liquid.txt"; }
}
public override void ExtractFromFile(string stringData)
{
this.Elements.Add(new Liquid(stringData));
}
}
public class GasBox : ElementBox<Gas>
{
public override string Filename
{
get { return "Gas.txt"; }
}
public override void ExtractFromFile(string stringData)
{
this.Elements.Add(new Gas(stringData));
}
}
public static class DataDefinition
{
public static SolidBox SolidBox { get; set; }
public static LiquidBox LiquidBox { get; set; }
public static GasBox GasBox { get; set; }
public static IElementBox[] ElementBoxes = new IElementBox[] { DataDefinition.SolidBox, DataDefinition.LiquidBox, DataDefinition.GasBox };
}
public static class Loader
{
public static void LoadInfo()
{
for (int elementBoxNb = 0; elementBoxNb < DataDefinition.ElementBoxes.Length; elementBoxNb++)
{
string dataFilepath = DataDefinition.ElementBoxes[elementBoxNb].Filename;
System.IO.StreamReader sr = System.IO.File.OpenText(dataFilepath);
DataDefinition.ElementBoxes[elementBoxNb].ExtractFromFile(sr.ReadToEnd());
}
}
}
The whole purpose of this structure is to be able to define all the object properties in a text file. So that all the SolidBox.Elements objects are dynamically assigned from that text file definition.
My questions are as follow:
Will the property array in DataDefinition be referenced by value. Which would mean that all my data assignation would get absorbed in the void?
If yes (or no..), is their a better way of doing the whole thing / What would be the best way to do it?
I've been working on that data structure for a while now I'm getting proud of what I could achieve. I would be sad if all that was done for nothing. Although, if one if you can provide me with a better/optimal way of doing the whole thing, I will be grateful and throw my code in my archive folder.
Also, keep in mind that this is an example of the data structure. It does not reflect exactly what my code looks like and is made so to ease comprehension and reading.
Don't hesitate to ask questions if more information is needed.
Deserialization (reading objects in from a persistent medium) has been solved a zillion different ways. Try using Data Contracts, like this answer demonstrates. You just need to add a few attributes to your properties to indicate what you want serialized and then it does just about all of the work for you.
This won't do what you want. The array will contain references to the objects referenced by the properties at the time it is initialised, which in this case will be null. If you assign something to the SolidBox property the associated element of the array won't change, and vice-versa.

Categories

Resources