I am having a bit of difficulty in understanding how the Container/Component model interacts with each other in C#. I get how the Component contains a Site object which has information about Container and Component. But, suppose I had the following code:
using System;
using System.ComponentModel;
public class Entity : Container {
public string Foo = "Bar";
}
public class Position : Component {
public int X, Y, Z;
public Position(int X, int Y, int Z){
this.X = X;
this.Y = Y;
this.Z = Z;
}
}
public class Program {
public static void Main(string[] args) {
Entity e = new Entity();
Position p = new Position(10, 20, 30);
e.Add(p, "Position");
}
}
This works without issue, it defines a Container (Entity) and a Component (Position) that is contained inside it.
However, if I invoke p.Site.Container, it will return Entity, but as IContainer. That is, I would have to explicitly do something like (Console.WriteLine(p.Site.Container as Entity).Foo); if I wanted to access Foo. This seems quite cumbersome.
Am I missing something, or is there a better way to do what I want?
You're not missing anything. There is no interface contract regarding what container a component can be inside. If you want to restrict what kind of components can be added to the container you can overload the Add method and do a check of the type of component being added:
public class Entity : Container {
public string Foo = "Bar";
public virtual void Add(IComponent component) {
if (!typeof(Position).IsAssignableFrom(component.GetType())) {
throw new ArgumentException(...);
}
base.Add(component);
}
}
Related
I have created an object that holds 4 properties, and will get created and used in Class A. However, I need to call some of the properties in 2 other classes (Class B and Class C). I'm not able to do this, and I'm confident that I am missing something very simple. Here is my object creation class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
public class ConfigItems
{
public static string W { get; set; }
public static string X { get; set; }
public static int Y { get; set; }
public static Int64 Z { get; set; }
public ConfigItems(string w, string x, int y, Int64 z) {
W= w;
X= x;
Y= y;
Z= z;
}
}
}
In my Main class, this is how I'm creating the object, which works just fine as long as I remain in the Main class:
namespace Test
{
public class Main
{
ConfigItems mainSetup = new ConfigItems(w, x, y, z);
console.writeline(mainSetup.x);
}
}
In the Main class when I create the object, I can keep calling it. When I move to a new class and try to call the same object, I cannot. It is out of scope, and I'm not certain as to why.
namespace SomeClass
{
public class StuffHere
{
Console.Writeline(mainSetup.x);
}
}
mainSetup.x in the above will not return anything, because it is out of scope. I have tried using both static and non-static properties in the object creation lass (ConfigItems) but I still can't call mainSetup.x outside of the Main class
You have defined your properties as static, therefore they are not instance members, but members of the class. Remove the static keyword.
public string X { get; set; }
Your class is not static! so you can't access class's property directly.
You have two way:
Make your class static.
public static class ConfigItems {
}
Pass the class context from initialer class (A) to other classes (B or C).
Class A:
ConfigItems mainSetup = new ConfigItems(w, x, y, z);
SecondClass b = new SecondClass(mainSetup);
Class B or C:
public class SecondClass {
public SecondClass (ConfigItems config) {
// You have the ConfigItems class here and you can do anything with it
}
}
you can access them directly using CalssName
ConfigItems.X;
Let s say I got an abstract class A. There I got some inner classes like here:
public abstract class A
{
public InnerOne x;
public InnerTwo y;
public A(){
this.x = new InnerOne();
this.y = new InnerTwo();
}
public class InnerOne
{
public virtual double value(){
return 0;
}
}
public class InnerTwo
{
public virtual double value(){
return 0;
}
}
}
Then I got it's childrens like this one:
public class B: A
{
public B():base(){
}
public class InnerOne: A.InnerOne
{
public override virtual double value(){
return 100;
}
}
public class InnerTwo: A.InnerTwo
{
public override virtual double value(){
return 100;
}
}
}
So I was think that when I call B constructor like that I will initialize x and y by creating it's inner classes instances. But actually it not works like that. When I call vaule functions like here it returns zeros.
A newobject = new B();
var bv1 = B.x.value();
var bv2 = B.y.value();
Is there way to force B class to initialize it's x and y fields by it's inner class objects (not with objects from parent abstract class) without re-writing it's constructor?
Even though you have defined the classes inside A or B, they are still public and they are accessible outside A or B. Its no different from a class definied outside A or B.
Imagine the same code with the InnerOne and InnerTwo defined outside the class A and B. It will have the same above behavior. Your root of confusion is misunderstanding inner class usage.
Inorder to get 100, inside B you need to explicitly replace the instance of X and Y variables with an instance that overrides those values. Unless you do them you will not get 100.
public class B: A
{
public B():base(){
X = new OverridenInnerOne();
Y = new OverridenInnerTwo();
}
public class OverridenInnerOne: A.InnerOne
{
public override virtual double value(){
return 100;
}
}
public class OverridenInnerTwo: A.InnerTwo
{
public override virtual double value(){
return 100;
}
}
}
You can do it, but you must change the definition for class A - and it gets super hairy.
Here's A:
public abstract class A<I1, I2>
where I1 : A<I1, I2>.InnerOne, new()
where I2 : A<I1, I2>.InnerTwo, new()
{
public InnerOne x;
public InnerTwo y;
public A()
{
this.x = new I1();
this.y = new I2();
}
public class InnerOne
{
public virtual double value()
{
return 0;
}
}
public class InnerTwo
{
public virtual double value()
{
return 0;
}
}
}
And here's B:
public class B: A<B.InnerOne, B.InnerTwo>
{
public B():base(){ }
public class InnerOne: A<InnerOne, InnerTwo>.InnerOne
{
public override double value()
{
return 100;
}
}
public class InnerTwo: A<InnerOne, InnerTwo>.InnerTwo
{
public override double value()
{
return 100;
}
}
}
B.x and B.y are instances of A.InnerOne and A.InnerTwo, so you're seeing the value returned as 0 as these have nothing to do with B.InnerOne or B.InnerTwo.
The following B constructor would assign x and y to instances of B.InnerOne and B.InnerTwo which would return 100.
public B(){
this.x = new InnerOne();
this.y = new InnerTwo();
}
If you wanted A to work in the way you expect, you'd need to pass the inner types you wanted through from the B constructor and create instances of them in the A constructor, something like:
public B():base(typeof(InnerOne),typeof(InnerTwo)) { ... }
Using Activator.CreateInstance will let you create these types within A's constructor.
Enigmativity's generic solution is better if you always want A used this way, alternatively this way allows you to have multiple constructors for A so you could optionally pass in different types.
The 'inner class' aspect (embedded class definition) only distracts here, it plays no role.
And to answer the question: No, you cannot have 'virtual constructors' that work this way.
There are of course plenty of ways to get 100 instead of 0 as returnvalue but the question is too artificial to suggest one.
We have a library containing a couple of assemblies with different functionality. We use this library in any frontend project we develop for our clients. Say I want to perform a particular task/method within the library, but the implementation of that method must be in the frontend.
In short: Class X in library calls method A of class Y in library, but method A needs to be implemented outside library. How?
You can expose a delegate from your lib and let consumers set it to point to their own implementation.
Example:
public delegate void DoWorkDelegate(CustomWorkParameters p);
public DoWorkDelegate DoWorkCallback
{
get
{
return _workCallback;
}
set
{
_workCallback = value;
}
}
Later in your lib, when you need to actually do the work:
private void DoWorkInternal()
{
//Some work here
//Check if caller set the callback
if(_workCallback != null)
{
_workCallback(localWorkParameters);
}
else
{
//throw exception
}
//Some more work here
}
Consumers should have a method respecting the delegate's signature and just pass it to your lib in the initialization phase.
Define ClassY as an Abstract class, requiring the consumer to provide an implementation for methods defined as Abstract. Logic defined on the ClassY base will be common to all derived classes, and methods defined on ClassY base as "abstract" will need to be implemented by each derived class. Note I hacked this together for example only, so I make no claim that the actual code represents best practices!
The Abstract base class:
public abstract class AbstractLibraryClassY
{
private static int _multiplier = 0;
public abstract int MethodA(int SomeParam);
// A simple example Property defined and implemented on the Abstract base class:
public int Multiplier
{
get { return _multiplier; }
set { _multiplier = value; }
}
private void someclassYImplementationStuff()
{
// Other implementation code . . .
}
}
Two possible implementations of ClassY:
public class ConcreteClassYImplementationOne : AbstractLibraryClassY
{
public override int MethodA(int SomeParam)
{
return SomeParam * this.Multiplier;
}
}
public class ConcreteClassYImplementationTwo : AbstractLibraryClassY
{
public override int MethodA(int SomeParam)
{
return SomeParam * this.Multiplier + 5;
}
}
Class X, Consumes instances of ClassY:
public class LibraryClassX
{
public int methodCallsClassYMethodA(AbstractLibraryClassY ImplementedClassY)
{
ImplementedClassY.Multiplier = 2;
return ImplementedClassY.MethodA(100);
}
}
A simple demonstration which uses class X to consume each implementation of ClassY in sequence:
public class Consumer1
{
public void ConsumeClassX()
{
// Some hokey, arbitrary inputs:
int MyInput = 200;
int MyMultiplier = 2;
// Consume Library Class Y using ConcreteClassYImplementationOne:
AbstractLibraryClassY InstanceOf = new ConcreteClassYImplementationOne();
InstanceOf.Multiplier = MyMultiplier;
// Will output 400, per implementation defined in ConcreteClassYImplementationOne:
Console.WriteLine("Output = " + InstanceOf.MethodA(MyInput).ToString());
// Consume Library Class Y using ConcreteClassYImplementationTwo:
InstanceOf = new ConcreteClassYImplementationTwo();
InstanceOf.Multiplier = MyMultiplier;
// Will output 405, per implementation defined in ConcreteClassYImplementationTwo:
Console.WriteLine("Output = " + InstanceOf.MethodA(MyInput).ToString());
}
}
Hope that helps. Also look into the commentor's suggestion re: Dependency Injection. I am only now looking into that (and it may be what I just described - not sure, gotta research!
I have a method:
private double FindPrice<T>(T l_Price_Breaks) where T : ?
{
}
The ? I want to limit to 3 classes X, Y, Z. These three classes inheric from a class called child:
public class X : Child
public class Y : Child
public class Z : Child
Can't I just do :
private double FindPrice<T>(T l_Price_Breaks) where T : Child
{
}
It works but when I try to call this method using the following:
X MyX = new X();
double return = FindPrice(MyX);
I get "There is no implicit conversion from X to Child".
The code works for me with one exception: You have a variable name called return, which does not work, since this is a reserved keyword in c#. Rename it to result.
You can, but you have another bunch of problems with your code, like
Identifier expected; 'return' is a keyword.
Public needs to be public, etc.
If you rewrite your code like this
class GenericTest
{
public class Child { }
public class X : Child { }
public class Y : Child { }
public class Z : Child { }
private double FindPrice<T>(T l_Price_Breaks) where T : Child
{
return 2;
}
private void foobar()
{
X MyX = new X();
double retValue = FindPrice(MyX);
}
}
It compiles fine.
You're missing some essential information like the implementation of FindPrice, but I'll take a guess that you're using Child instead of T in the body of the FindPrice method.
I have a class whereby a method calls a nested class. I want to access the parent class properties from within the nested class.
public class ParentClass
{
private x;
private y;
private z;
something.something = new ChildClass();
public class ChildClass
{
// need to get x, y and z;
}
}
How do I access x,y and z from within the child class? Something to do with referencing the parent class, but how?
Use the this keyword to pass a reference to 'yourself' to the constructor of the ChildClass.
public class ParentClass
{
public X;
public Y;
public Z;
// give the ChildClass instance a reference to this ParentClass instance
ChildClass cc = new ChildClass(this);
public class ChildClass
{
private ParentClass _pc;
public ChildClass(ParentClass pc) {
_pc = pc;
}
// need to get X, Y and Z;
public void GetValues() {
myX = _pc.X
...
}
}
}
See http://www.codeproject.com/KB/cs/nested_csclasses.aspx for a detailed tutorial on using nested classes in C#. I think you're looking for something like:
class OuterClass
{
public int y = 100;
public class NestedClass
{
public static void abc()
{
OuterClass oc = new OuterClass();
System.Console.WriteLine(oc.y);
}
}
}
So, in order to access the fields of the outer class, you need an instance of the outer class available to the inner class.
Keep in mind that you can access static fields from the inner class without an instance of the outer class around:
class OuterClass
{
public static int y = 100;
public class NestedClass
{
public static void abc()
{
System.Console.WriteLine(OuterClass.y);
}
}
}
You need to pass in a reference to the parent class instance, for instance in the constructor of ChildClass. Of course you can access fields of ParentClass if those are static.
Note: If you have ever done Java, C# only supports the notion of the "static" inner class.
Well, on the constructor of your nested class pass in a reference to the outer class.
That way you can access the parent class properties from within the nested class.
Also, it's worth noting that static properties from the parent class, are available to you.
http://en.csharp-online.net/Nested_Classes
Example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Application {
class OuterClass {
int someProperty = 10;
class NestedClass {
OuterClass reference;
public NestedClass( OuterClass r ) {
reference = r;
}
public void DoSomething( ) {
Console.Write( reference.someProperty );
}
}
public OuterClass( ) {
NestedClass nc = new NestedClass( this );
nc.DoSomething( );
}
}
class Test {
public static void Main( string[] args ) {
OuterClass oc = new OuterClass( );
}
}
}