Might look a silly question, but can I return an instance?
Example:
public class EcranJeu : AffichageJeu
{
public EcranJeu(string choixecran)
{
if (choixecran == "0")
{
KystExtract décor = new KystExtract();
}
if (choixecran == "1")
{
KystExtraction décor = new KystExtraction();
}
}
public override void LoadContent()
{
décor.LoadContent(content);
}
}
décor is said not to exist. How can I pass it to the LoadContent, Update and Draw of all the class?
If I understand it correct you just want to create a instance member in the constructor and access it in LoadContent, Update and Draw?
public class EcranJeu : AffichageJeu
{
private KystExtract décor;
public EcranJeu(string choixecran)
{
if (choixecran == "0")
{
décor = new KystExtract();
}
if (choixecran == "1")
{
décor = new KystExtraction();
}
}
public override void LoadContent()
{
décor.LoadContent(content);
}
}
if you want to access the property from an other instance than create a getter and setter or declare the property public.
private KystExtract _décor;
public public string décor
{
//set the person name
set { this._décor = value; }
//get the person name
get { return this._décor; }
}
The other answer was only partially correct as you found.
Problem: You are creating an object of one of two different classes and later want to call a LoadContent(), or Draw() or Update() method on the chosen object.
I have to assume the two classes KystExtract and KystExtraction have a common base class or share an interface. If not you will need to create/add one (e.g. KrystBase or IKryst) that defines the LoadContent() method.
The property you store is then of the base class type/interface, so it can hold either a KystExtract object or a KystExtraction object.
Your code will look like this (assuming you have no common base class and use an interface):
public class EcranJeu : AffichageJeu
{
private IKystObject décor; // for example
public EcranJeu(string choixecran)
{
if (choixecran == "0")
{
décor = new KystExtract();
}
if (choixecran == "1")
{
décor = new KystExtraction();
}
}
public override void LoadContent()
{
décor.LoadContent(content);
}
}
// Common interface for classes requiring shared behavior
public interface IKystObject
{
public override void LoadContent();
public override void Update();
public override void Draw();
}
// Both classes implement your common interface
public class KystExtract : IKrystObject
{
... Implementation of LoadContent, Update and Draw
}
// Both classes implement your common interface
public class KystExtraction : IKrystObject
{
... Implementation of LoadContent, Update and Draw
}
Related
I have sample object model as below.
[AttributeUsage(AttributeTargets.Method)]
public sealed class CandidateApiForMenuItem : Attribute
{
public CandidateApiForMenuItem(string caption)
{
this.Caption = caption;
}
public string Caption { get; set; }
}
public class FormDataElementBase
{
public FormDataElementBase()
{
}
[CandidateApiForMenuItem("Add PanelGroup")]
public void AddPanelGroup()
{
///...
}
[CandidateApiForMenuItem("Add BoxGroup")]
public void AddBoxGroup()
{
///...
}
[CandidateApiForMenuItem("Remove")]
public void Remove()
{
///...
}
public void GenerateGroupPopupMenuItems()
{
foreach (MethodInfo methodInfo in this.GetType().GetMethods())
{
if (methodInfo.GetCustomAttribute(typeof(CandidateApiForMenuItem)) != null)
{
// This is true both for FormDataElementBase and all derived
// but I want to hide Remove method inside MainGroup class
// However it is displayed again
};
};
}
}
public class BoxGroup : FormDataElementBase
{
}
public class PanelGroup : FormDataElementBase
{
}
public class MainGroup : FormDataElementBase
{
private void Remove()
{
}
}
When user right click, application will display PopupMenu (GenerateGroupPopupMenuItems method). Items of menu will be based on methods who has CandidateApiForMenuItem declared. However, there are derived class (MainGroup) where some methods (f.e: Remove) should not be displayed. What I did, inside MainGroup declared Remove method as private. However, it is displayed again.
Could you pls let me know what I am doing worng here?
Thanks.
First of all, this.GetType().GetMethods() without parameters returns only public instance (i.e. non-static) methods. So MainGroup.Remove won't be returned by this call.
If you make MainGroup.Remove public, this.GetType().GetMethods() will return both methods - for base class and for derived one. Not what you want, I suppose.
If you make FormDataElementBase.Remove virtual and MainGroup.Remove override, GetMethods will return only one Remove method (with DeclaringType==typeof(MainGroup)) - this is better.
And finally, I'd suggest to introduce one more attribute, say, CandidateApiIgnore. If we mark an overridden method with this attribute and modify in the following way GenerateGroupPopupMenuItems method, the stuff should work:
[AttributeUsage(AttributeTargets.Method)]
public sealed class CandidateApiIgnore : Attribute
{
public CandidateApiIgnore() { }
}
public class FormDataElementBase
{
///...
[CandidateApiForMenuItem("Remove")]
public virtual void Remove()
{
///...
}
public void GenerateGroupPopupMenuItems()
{
foreach (MethodInfo methodInfo in this.GetType().GetMethods())
{
if (methodInfo.GetCustomAttribute(typeof(CandidateApiForMenuItem)) != null &&
methodInfo.GetCustomAttribute(typeof(CandidateApiIgnore)) == null)
{
// If a method is overridden and marked with
// CandidateApiIgnore attribute in a derived
// class, it won't be processed here.
};
};
}
public class MainGroup : FormDataElementBase
{
[CandidateApiIgnore]
public override void Remove()
{
throw new NotSupportedException();
}
}
Is there a way to force the override of a virtual method if another method is overriden?
public class BaseClass
{
protected virtual void A()
{
// a default action called first
}
protected virtual void B()
{
// a default action called second that,
// if A was overriden, makes no sense
}
}
EDIT
Thanks a lot for the Answers. It's very interresting to see how this could be achieved, but for my explicit case it's not critically important.
Also, i forgot to mention how those Methods would be used: (in BaseClass)
pulbic bool EditEntity(Guid id)
{
A();
// Some code that edits Entites
B();
}
No, you cannot. But this makes me think how could you achieve the same concept?
The best idea I came up with was declaring an interface which had the package of methods to override.
public interface IMyOverridablePackage
{
void A_Override();
void B_Override();
}
Then give the base class a protected method where the child class can explicitly override the set of methods.
protected void SetOverride(IMyOverridablePackage overridablePackage)
{
_overridablePackage = overridablePackage;
}
So then here's two classes, one which does and one which does not override the set of methods:
public class NotOverriding : MyBaseClass
{
}
public sealed class Overriding : MyBaseClass, IMyOverridablePackage
{
public Overriding()
{
SetOverride(this);
}
void IMyOverridablePackage.A_Override()
{
Console.WriteLine("Overriding.A_Override");
}
void IMyOverridablePackage.B_Override()
{
Console.WriteLine("Overriding.B_Override");
}
}
And the implementation of the base class:
public abstract class MyBaseClass
{
private IMyOverridablePackage _overridablePackage;
public void A()
{
_overridablePackage.A_Override();
}
public void B()
{
_overridablePackage.B_Override();
}
private class MyDefaultPackage : IMyOverridablePackage
{
private readonly MyBaseClass _myBaseClass;
internal MyDefaultPackage(MyBaseClass myBaseClass)
{
_myBaseClass = myBaseClass;
}
void IMyOverridablePackage.A_Override()
{
_myBaseClass.A_Impl();
}
void IMyOverridablePackage.B_Override()
{
_myBaseClass.B_Impl();
}
}
protected MyBaseClass()
{
_overridablePackage = new MyDefaultPackage(this);
}
private void A_Impl()
{
Console.WriteLine("MyBaseClass.A_Impl");
}
private void B_Impl()
{
Console.WriteLine("MyBaseClass.B_Impl");
}
protected void SetOverride(IMyOverridablePackage overridablePackage)
{
_overridablePackage = overridablePackage;
}
}
This does achieve the goal, but of course you have to ask 'how much to I want it?' Is it worth the extra code?
Here's a working dotnetfiddle: https://dotnetfiddle.net/xmPn20
Maybe you cannot force it via compiler errors, but you could write a test which asserts that the methods are in sync via some attributes. It would also be visible that there is some dependency.
A crude example would be something like this:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class VersionAttribute : Attribute
{
public VersionAttribute(string version)
{
Version = version;
}
public string Version { get; set; }
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class DependentAttribute : Attribute
{
public string DependentOnMethod { get; set; }
public string DependentOnVersion { get; set; }
}
[Dependent(DependentOnMethod = "OtherMethod", DependentOnVersion = "1")]
public static void FirstMethod()
{
}
[Version("1")]
public static void OtherMethod()
{
}
And the test that asserts the version numbers:
[Test]
public void TestVersions()
{
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
foreach (var method in type.GetMethods())
{
foreach (var customAttribute in method.GetCustomAttributes())
{
var dependent = customAttribute as DependentAttribute;
if (dependent != null)
{
var methodInfo = type.GetMethod(dependent.DependentOnMethod);
Assert.That(methodInfo, Is.Not.Null, "Dependent method not found");
VersionAttribute version = methodInfo.GetCustomAttributes().OfType<VersionAttribute>().FirstOrDefault();
Assert.That(version, Is.Not.Null, "No version attribute on dependent method");
Assert.That(dependent.DependentOnVersion, Is.EqualTo(version.Version));
}
}
}
}
}
thus, if you update one of your methods you would need to update the version number of either the Version attribute or the Dependent attribute. Hopefully better than nothing.
You may change your design :
public abstract class BaseClass
{
protected abstract void A();
}
public class BaseClassEx
{
protected sealed override void A()
{
// action Calling B
}
protected virtual void B()
{
// a default action called second
}
}
In the case of Equals (actually both Equals overloads, concrete type and object) and GetHashCode, Resharper includes a rule that shows a warning in its IntelliSense whenever you forget to implement one of these.
You could enforce it in your code with a runtime check in the constructor of the base class:
public class Base
{
public Base()
{
var baseA = typeof (Base).GetRuntimeMethod("MethodA", new Type[0]);
var baseB = typeof (Base).GetRuntimeMethod("MethodB", new Type[0]);
var derivedA = GetType().GetRuntimeMethod("MethodA", new Type[0]);
var derivedB = GetType().GetRuntimeMethod("MethodB", new Type[0]);
if (baseA.DeclaringType == derivedA.DeclaringType ^
baseB.DeclaringType == derivedB.DeclaringType)
throw new InvalidOperationException("You must override MethodA and MethodB together.");
}
public virtual string MethodA() { return "Hello"; }
public virtual int MethodB() { return 123; }
}
I have the following classes, and when I call CreateQuerySettings on the BaseScriptConfigurationList, it returns the new QuerySettings from ConfigurationList, rather than the HierarchicalQuerySettings value in BaseScriptConfigurationList:
public abstract class ConfigurationList<TConfigurationObject, TPropertyEnum>
{
public QuerySettings<TConfigurationObject, TPropertyEnum> CreateQuerySettings()
{
return new QuerySettings<TConfigurationObject, TPropertyEnum>();
}
}
public class BaseScriptConfigurationList : EditableConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
public BaseScriptConfigurationList(ConfigurationManager configurationManager)
: base(configurationManager, InternalAdminObjectType.BaseScript)
{
_BaseScriptPageListWatcher = new ConfigurationList<BaseScriptPageConfiguration, BaseScriptPageConfiguration.Property>.
ConfigurationWatcher(null);
_ConfigurationWatcher.ChildWatchers.Add(_BaseScriptPageListWatcher);
}
public new QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property, BaseScriptQueryChildrenSettings>();
}
}
Edit: I make the call from another class where TConfigurationObjectList is BaseScriptConfigurationList. I've added the constructor to the code above so you can see what it's doing. Please note that EditableConfigurationList inherits from ConfigurationList.
TConfigurationObjectList cl = (TConfigurationObjectList)typeof(TConfigurationObjectList).GetConstructor(new Type[] { typeof(ConfigurationManager) }).Invoke(new object[] { Manager.ConfigurationManager });
var querySettings = cl.CreateQuerySettings();
When I make this call, it goes into the ConfigurationList.CreateQuerySettings method.
How can I hide the CreateQuerySettings method, so that when I call it from the BaseScriptConfigurationList class, I get a HierarchicalQuerySettings object?
The new modifier can be beasty. Note that you are hiding and not overriding in your example. You are not showing that part of the code, but I assume you have this situation:
class Base
{
public static void BaseMethod() { Console.WriteLine("BASE!"); }
}
class Derived : Base
{
// Hides Base.BaseMethod()
new public static void BaseMethod() { Console.WriteLine("DERIVED!"); }
}
Base a = new Base();
a.BaseMethod(); // -> "BASE!"
Base b = new Derived();
b.BaseMethod(); // -> "BASE!"
Derived b = new Derived();
b.BaseMethod(); // -> "DERIVED!"
In BaseScriptConfigurationList.CreateQuerySettings()
you're return type is QuerySettings<T,T> so you will always get that type as a return value, but you are returning a HierarchicalQuerySettings. You can one, change the return type of CreateQuerySettings() to HierarchicalQuerySettings or two, cast the object to its child type "HierarchicalQuerySettings". If you really want to hide it, you can do this:
public class newclass : BaseScriptConfigurationList
{
public new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return (HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property>)base.CreateQuerySettings();
}
}
But that doesn't really seem efficient and i advise against it. Like i said, i maybe missing some other requirement, but based on the info that you gave..
Basically, what I'm seeing (and making assumptions) that TConfigurationObjectList Inhertis from ConfigurationList somewhere along the lines, so on and so forth, all the way up to EditableConfigurationList. since you are dynamically creating an instance of the class TConfigurationObjectList, and calling the method from that point, you will be calling the base ConfigurationList member CreateQuerySettings. You do not have access to the new CreateQuerySettings. If you are creating the class BaseScriptConfigurationList instance at this point, cast the object ((BaseScriptConfigurationList)cl).CreateQuerySettings(). That being said. if you do not know what you have at runtime:
var obj = typeof(TConfigurationObjectList).GetConstructor(new Type[] { typeof(ConfigurationManager) }).Invoke(new object[] { Manager.ConfigurationManager });
var cl = (obj as BaseScriptConfigurationList) ?? (TConfigurationObjectList)obj;
// or do something else
var querySettings = cl.CreateQuerySettings();
Note i am assuming your architecture is roughly set up like this:
public abstract class ConfigurationList<TConfigurationObject, TPropertyEnum>
{
public QuerySettings<TConfigurationObject, TPropertyEnum> CreateQuerySettings()
{
return new QuerySettings<TConfigurationObject, TPropertyEnum>();
}
}
public class TConfigurationObjectList : ConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
}
public class EditableConfigurationList<T, T1> : TConfigurationObjectList
{
protected EditableConfigurationList(ConfigurationManager configurationManager, object baseScript)
{
throw new NotImplementedException();
}
}
public class BaseScriptConfigurationList : EditableConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
public BaseScriptConfigurationList(ConfigurationManager configurationManager)
: base(configurationManager, InternalAdminObjectType.BaseScript)
{
}
public new QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property, BaseScriptQueryChildrenSettings>();
}
}
public class QuerySettings<T, T1>
{
}
public class HierarchicalQuerySettings<T, T1, T2> : QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
}
public class BaseScriptQueryChildrenSettings
{
}
public class BaseScriptPageConfiguration
{
public class Property
{
}
}
public class InternalAdminObjectType
{
public static object BaseScript { get; set; }
}
public class ConfigurationManager
{
}
public class BaseScriptConfiguration
{
public class Property
{
}
}
Create a base interface for the ConfigurationList class (say IConfigurationList) and use this interface as the data type for the variable cl instead of TConfigurationList.
I'm totally new to C# generic so I have the following problem. I have 2 classes. One instance based and another generic class.
I want to have a property in the 1st class of the type of 2nd generic class.
something on these lines....functionality wise.
public class SampleClass
{
private SampleGenericClass<T> sampleClass;
public SampleClass(string name, int age, string version)
{
if(version == "1.0")
{
this.sampleClass = new SampleGenericClass<int>(name, age);
}
else
{
this.sampleClass = new SampleGenericClass<long>(name.age);
}
}
public void Load()
{
this.sampleClass.Load();
}
public void Open()
{
this.sampleClass.Open();
}
public void Close()
{
this.sampleClass.Close();
}
}
My 2nd generic class is something like this
internal class SampleGenericClass<T> where T : class
{
private string name;
private string age;
public SampleGenericClass(string name, int age)
{
this.name = name;
this.age = age;
}
public void Load()
{
// Do something based on type
if(typeof(T) == typeof(int))
{
// load int type
}
else if(typeof(T) == typeof (long))
{
// load long type
}
else
{
throw new ArgumentException("Un supported type");
}
}
public void Open()
{
// Do something based on type
if(typeof(T) == typeof(int))
{
// open int type
}
else if(typeof(T) == typeof (long))
{
// open long type
}
else
{
throw new ArgumentException("Un supported type");
}
}
public void Close()
{
// Do something based on type
if(typeof(T) == typeof(int))
{
// close int type
}
else if(typeof(T) == typeof (long))
{
// close long type
}
else
{
throw new ArgumentException("Un supported type");
}
}
}
Now I understand that CLR doesnt support generic properties or constructors.
So how can I solve this problem? I still want to have a generic class and somehow instantiate it in my 2nd class based on the params passed to constructor of 1st class, so as to call the methods load,openm, close in the 2nd class .
Thanks for your help.
NOTE: I know the above code doesn't compile, bcoz CLR doesnt support generic properties and constructors. It's just for illustrative purpose of what I want to achieve conceptually
IMO you should decide in upper level, what is the type of SampleClass In fact you should define it as generic:
public class SampleClass<T> where T : ....
{
private SampleGenericClass<T> sampleClass;
public SampleClass(string name, int age, string version)
{
this.sampleClass = new SampleGenericClass<T>(name, age);
}
public void Load()
{
this.sampleClass.Load();
}
}
and create your SampleClass base on version in upper levels(and related generic).
e.g:
Main method:
if (version == "1")
{
DoAction<int>();
}
else
DoAction<long>();
.....
void DoAction<T>()
{
SampleClass<T> s = new SampleClass<T>(...)
}
Also as I can see you don't need T type for your member variables, so you can move it to lower level in function calls.
Either declare a concrete type
public class SampleClass {
private SampleGenericClass<int> sampleClass;
...
}
or add a generic type parameter to SampleClass
public class SampleClass<T> where T : class {
private SampleGenericClass<T> sampleClass;
...
}
Interface:
public interface ISampleGenericClass
{
void Load();
void Open();
void Close();
}
The generic class implements this:
internal class SampleGenericClass<T> : ISampleGenericClass
{
...
}
And SampleClass
public class SampleClass
{
private ISampleGenericClass sampleClass;
....
}
I removed the class constraint, because int and long are value types, so they can't be used in the current form.
Hi I am new to design pattern and apologize if this question is creating any confusion although i am trying to describe the issue in best possible way.I have implemented sample abstract factory pattern in winforms. Front end contains two check boxes to create the objects. Note: If both the check box are checked, both the objects are created.
I am using objs.CreateProduct(Maxima,Ultima) method and passing the boolean values to create the objects. Here I am passing the values of both the properts whether I want to create object for ultima or maxima. Can you suggest any other better way to achieve this ? I don't want to pass the properties for maxima and ultima if I am creating the objects.
public partial class Form1 : Form
{
public bool Maxima
{
get;
set;
}
public bool Ultima
{
get;
set;
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Factory[] obj = new Factory[2];
obj[0] = new B();
obj[1] = new C();
foreach (Factory objs in obj)
{
iProduct prod = objs.CreateProduct(Maxima,Ultima);
if (prod != null)
{
prod.GetDetails();
}
}
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (checkBox2.Checked)
Maxima = true;
else
Maxima = false;
if (checkBox1.Checked)
Ultima = true;
else
Ultima = false;
}
}
abstract class Factory
{
public abstract iProduct CreateProduct(bool maxima, bool ultima);
}
class B : Factory
{
public override iProduct CreateProduct(bool maxima,bool ultima)
{
if (ultima)
{
return new NissanUltima();
}
else return null;
}
}
class C : Factory
{
public override iProduct CreateProduct(bool maxima,bool ultima)
{
if (maxima)
{
return new NissanMaxima();
}
else return null;
}
}
interface iProduct
{
void GetDetails();
}
class NissanUltima:iProduct
{
public void GetDetails()
{
MessageBox.Show("NissanUltima is created");
}
}
class NissanMaxima:iProduct
{
public void GetDetails()
{
MessageBox.Show("NissanMaxima is created");
}
}
I would suggest to redesign that code. Abstract Factory is to create an abstract product say a car in your sample. A specific factory addss a trait of the product. Lets say Nissanfactory and Fordfactory
then in each CreateFactory() you may scecify a model of the car you want to create.
abstract class Factory
{
public abstract iProduct CreateProduct(int Model);
}
class NissanFactory : Factory
{
public override iProduct CreateProduct(int Model)
{
// say 1 is Maxima
//say 2 is Untima
if (Model ==1)
{
return new NissanMaxima();
}
if(Model ==2)
{
return new NissanUltima();
}
return null;
}
}
class FordFartory : Factory
{
public override iProduct CreateProduct(int Model)
{
if (Model == 1)
{
return new GrandTorino();
}
if (Model == 2)
{
return new Mustang();
}
return null;
}
}
//
private void button1_Click(object sender, EventArgs e)
{
Factory[] obj = new Factory[1];
obj[0] =new NissanFactory();
private List<iProduct> products = new List<iProduct>();
//create maxima if it's chacked
if (checkBox2.Checked)
products.Add(obj.CreateProduct(1));
//create ultima
if (checkBox1.Checked)
products.Add(prod = obj.CreateProduct(2));
//now you can navigate via list of created products
foreach (IProduct car in products)
{
prod.GetDetails();
}
}
A factory base class interface should be allow clients to create any kind of descendant instance, based only on the parameters provided to its create method. The whole point is decoupling object creation from knowledge about specific concrete types, in order to allow e.g. dependency injection.
If you want to provide distinct initialization data to various descendant factories, that data should be contained in or provided to the factory class itself (since whatever code is creating and configuring the factories is the only part that should know about the concrete type). So, initialize B with the bool value for Ultima and C with the value of Maxima.
Frankly, you may have edited your example a bit too heavily: I'm not really sure of what you are trying to do. If the WinForms code should be unaware of the concrete types, you're going to need to introduce some kind of decoupling interface between that and your factory creation code in order to pass initialization data.