I'm writing my first PS Module in C# over the past few days and this is extremely new to me. I had some trouble coming up with this to be honest (maybe not enough caffeine) but I've come to a solution now however I'm hoping someone may have some more elegant ideas?
i'm finding some of the documentation regarding powershell to be a little vague, at least with regard to creating modules in C#. Embedding C# in PowerShell, no problem, running powershell code within C#, also tons of information, but information on writing PS modules in C# seems scarce, or I'm looking in the wrong places?
Enough chatter, here's my situation. First, I have a quick and dirty new and get cmdlet sample below.
[Cmdlet(VerbsCommon.New, "TestItem")]
[OutputType(typeof(TestItem))]
public class NewItem : Cmdlet
{
[Parameter(Position = 0)]
public string FriendlyName
{
get { return friendlyname; }
set { friendlyname = value; }
}
private string friendlyname;
[Parameter(Position = 1)]
public string Name
{
get { return name; }
set { name = value; }
}
private string name;
[Parameter(Position = 2)]
public int ID
{
get { return id; }
set { id = value; }
}
private int id;
private TestItem item;
protected override void BeginProcessing()
{
item = new TestItem();
}
protected override void ProcessRecord()
{
item.Name = name;
item.FriendlyName = friendlyname;
item.ID = id;
}
protected override void EndProcessing()
{
WriteObject(item);
}
}
[Cmdlet(VerbsCommon.Get, "TestItem")]
[OutputType(typeof(TestItem))]
public class GetItem : Cmdlet
{
[Parameter(Position = 0)]
public string[] FriendlyName
{
get { return friendlyname; }
set { friendlyname = value; }
}
private string[] friendlyname;
[Parameter(Position = 1)]
public List<TestItem> Item { get; set; }
[Parameter(ValueFromPipeline = true)]
public PSObject InputObject
{
set { inputObject = value; }
get { return inputObject; }
}
private PSObject inputObject;
private List<TestItem> item;
protected override void BeginProcessing()
{
item = new List<TestItem>();
}
protected override void ProcessRecord()
{
WriteVerbose("processing pipline");
if (inputObject != null)
{
WriteObject(inputObject.ToClassObject<TestItem>());
}
}
protected override void EndProcessing()
{
WriteObject(item);
}
}
Then I have my quick and dirty sample Object class
public class TestItem
{
public TestItem()
{ }
public string Name { get; set; }
public string FriendlyName { get; set; }
public int ID { get; set; }
}
And now this is where I'm looking for feedback. From the above we can see that the new-item creates an item, and when passed to get-item via the pipeline it's passed as a PSObject. My goal is to turn it back into the class object it started as, but I need to be able to handle Class/type dynamically as I intend to use this as a helper for a project I'm working on. I'm really just looking for feedback as I feel like there's a more elegant solution here?
public static class Helper
{
public static T ToClassObject<T>(this PSObject pso) where T : class, new()
{
try
{
T obj = new T();
foreach (PSPropertyInfo psPropertyInfo in pso.Properties)
{
foreach (var prop in obj.GetType().GetProperties())
{
try
{
if (psPropertyInfo.Name == prop.Name)
{
PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name);
propertyInfo.SetValue(obj, Convert.ChangeType(psPropertyInfo.Value, propertyInfo.PropertyType), null);
}
}
catch
{
continue;
}
}
}
return obj;
}
catch
{
return null;
}
}
}
OK, what you are working on is called binary modules / binary cmdlets, that probably a word for googling (it gets me a good number of articles about that). You can also find a bunch of real life examples on Powershell Core github, for example here.
From the other side it doesn't seem to be a very common way of creating cmdlets for powershell though, and in my opinion are much more complicated than pure PS code.
Regarding to your question, as I understand your Get-Item cmdlet is getting PSObject from the pipeline, and you need to convert it to custom type using input property names. If so you probably can use ValueFromPipelineByPropertyName property instead of ToClassObject. I'm not any kind of expert in C# or binary module writing, so I'll give my example in pure PS, I hope it's not a huge problem to convert it to C#
function Get-Column { [CmdletBinding()]param(
[parameter(ValueFromPipelineByPropertyName=$true)][String]$columnName,
[parameter(ValueFromPipelineByPropertyName=$true)][String]$type
)
Process { Write-Output (New-Object System.Data.DataColumn #($columnName, $type))}
}
$ObjectList = #(
New-Object psobject -Property #{columnName="FirstName"; type="String"}
New-Object psobject -Property #{columnName="LastName"; type="String"}
New-Object psobject -Property #{columnName="Age"; type="Int32"}
)
$ObjectList | Get-Column | Format-Table
So that cmdlet collects parameter values from input object and pass it to your custom class constructor. Also, I don't really need Begin and End blocks, probably those are redundant in your code as well.
As Mike Twc says, you are creating binary cmdlets. They are less frequently used and I, personally, think it is a shame because I see so many "PowerShell" scripts that look like C#, and binary cmdlets allow for native, more strongly-typed use in other C# applications. So kudoos for trying.
I think your major problem is what type you are specifying where. For elegance, you really don't need to be so verbose in the way you write your properties.
So here is a more elegant re-write that should solve your issue:
[Cmdlet(VerbsCommon.New, "TestItem")]
[OutputType(typeof(TestItem))]
public class NewItem : Cmdlet
{
[Parameter(Position = 0)]
public string FriendlyName { get; set; }
[Parameter(Position = 1)]
public string Name { get; set; }
[Parameter(Position = 2)]
public int ID { get; set; }
protected override void ProcessRecord()
{
var item = new TestItem();
item.Name = Name;
item.FriendlyName = Friendlyname;
item.ID = ID;
WriteObject(item);
}
}
[Cmdlet(VerbsCommon.Get, "TestItem")]
[OutputType(typeof(TestItem))]
public class GetItem : Cmdlet
{
// what is the point of this parameter since it is never used?
// Is it supposed to filter? If so, I would suggest using
// `Where-Object FriendlyName -In "MyName1","MyName2","MyName3"`
// instead of trying to write your own...
[Parameter(Position = 0)]
public string[] FriendlyName { get; set; }
// This parameter is unused and, likely, is what you
// intend for the InputObject parameter
//[Parameter(Position = 1)]
//public List<TestItem> Item { get; set; }
// Whatever this type is, because it is ValueFromPipeline,
// is what the pipeline input will be converted to
[Parameter(ValueFromPipeline = true)]
public TestItem InputObject { get; set; }
private List<TestItem> items;
protected override void BeginProcessing()
{
items = new List<TestItem>();
}
protected override void ProcessRecord()
{
WriteVerbose("processing pipline");
if (InputObject != null)
{
// do you actually mean `items.add(InputObject);`?
WriteObject(InputObject);
}
}
protected override void EndProcessing()
{
// this is empty because it never has elements added?
WriteObject(items, enumerateCollection: false);
}
}
Now another comment: The Get- verb, and you can see this in MS Doc, should act similarly to the New- verb in that it gets the instances already in the system, but is different in that it does not instantiate new instances. I am not fully sure what you are trying to do, since you seem to hand off the input object to later in the pipeline, which it otherwise would already be going to without the cmdlet--unless you are doing what my comments suggest and gathering them all into a list, and outputing the list
Related
Thanks in advance!
We have some Automation tests using the selenium web driver which are great and provide a really good regression pack.
The problem is now we have feature toggles in our code. So I need to say ignore these tests unless that feature toggle is turned On/ Off. I can't find anything really searching Google.
Ideally I don't want a 'if' statement at the top of the Feature tests but it looks like it's going to be the main way. My initial thoughts where to create a custom attribute
public class IsFeatureFlagTurnedOn : Attribute
{
public IsFeatureFlagTurnedOn(string featureToggleName)
{
FeatureToggleName = featureToggleName;
}
public string FeatureToggleName {get;}
}
public class MyTests
{
[TestMethod]
[IsFeatureFlagTurnedOn("MyFeature1")]
public void ItShould()
{
// only run if MyFeature1 is turned on
}
}
I some how need to hook into the MSTest pipeline and say if this attribute is present and the logic for MyFeature1 is turned off then don't run this test - Looked at dynamically adding the [Ignore] but with no luck.
This is running through VSTS and I could use [TestCategories] but I'd have to keep updating the pipeline to which feature is turned on/off which I don't want to do.
Any help or suggestions would be great!
MSTest v2 now has a lot of extensibility points, and you can achieve this by extending the TestMethodAttribute. First we add two attribute arguments, a string for a property name and a Type that has the property. Then we override the Execute method and invoke the property via reflection. If the result is true, we'll execute the test as normal, otherwise we return an 'inconclusive` test result.
public class TestMethodWithConditionAttribute : TestMethodAttribute
{
public Type ConditionParentType { get; set; }
public string ConditionPropertyName { get; set; }
public TestMethodWithConditionAttribute(string conditionPropertyName, Type conditionParentType)
{
ConditionPropertyName = conditionPropertyName;
ConditionParentType = conditionParentType;
}
public override TestResult[] Execute(ITestMethod testMethod)
{
if (ConditionParentType.GetProperty(ConditionPropertyName, BindingFlags.Static | BindingFlags.Public)?.GetValue(null) is bool condiiton && condiiton)
{
return base.Execute(testMethod);
}
else
{
return new TestResult[] { new TestResult { Outcome = UnitTestOutcome.Inconclusive } };
}
}
}
Now we can use our new attribute like this:
[TestClass]
public class MyTests
{
[TestMethodWithCondition(nameof(Configuration.IsMyFeature1Enabled), typeof(Configuration))]
public void MyTest()
{
//...
}
}
public static class Configuration
{
public static bool IsMyFeature1Enabled => false;
}
The above is a very generic solution. You could also customize it a little more to your particular use case to perhaps avoid quite so much verbosity in the attribute declaration:
public class TestMethodForConfigAttribute : TestMethodAttribute
{
public string Name { get; set; }
public TestMethodForConfigAttribute(string name)
{
Name = name;
}
public override TestResult[] Execute(ITestMethod testMethod)
{
if (IsConfigEnabled(Name))
{
return base.Execute(testMethod);
}
else
{
return new TestResult[] { new TestResult { Outcome = UnitTestOutcome.Inconclusive } };
}
}
public static bool IsConfigEnabled(string name)
{
//...
return false;
}
}
And use it like:
[TestClass]
public class MyTests
{
[TestMethodForConfig("MyFeature1")]
public void MyTest()
{
//...
}
}
Based on my reading of this, you may need to use Assert.Inconclusive
I have class which have too many related calculated properties.
I have currently kept all properties are read only.
some properties need long calculation and it is called again when its related properties are needed.
How can create this complex object .Also i want these properties should not be set from external code. I need show hide as i am binding properties for UI. Also i think order is also important.
My Class is something like
public string A
{
get
{
return complexMethod();
;
}
}
public string B
{
get
{
if (A == "value")
return "A";
else return "B";
;
}
}
public bool ShowHideA
{
get
{
return string.IsNullOrEmpty(A);
;
}
}
public bool ShowHideB
{
get
{
return string.IsNullOrEmpty(B);
;
}
}
public string complexMethod()
{
string value = "";
// calculation goes here
return value;
}
}
Thanks
You need to use Lazy type provided by .net:
Lazy<YourType> lazy = new Lazy<YourType>();
Make your properties internal to not be set from external code.
Well tall order isn't it?
One of the coolest things about extension methods is you can use types. This is perfect for writing external programs to calculate property values. Start like this...
public static class XMLibrary
{
public static MC CalculateValues(this MC myclass)
{
//for each property calculate the values here
if (myclass.Name == string.Empty) myclass.Name = "You must supply a name";
if (myclass.Next == 0) myclass.Next = 1;
//when done return the type
return myclass;
}
}
public class MC
{
public string Name { get; set; }
public int Next { get; set; }
}
public class SomeMainClass
{
public SomeMainClass()
{
var mc = new MC { Name = "test", Next = 0 };
var results = mc.CalculateValues();
}
}
There are many other ways to do class validation on a model, for example dataannotations comes to mind, or IValidatableObject works too. Keeping the validation separate from the class is a good idea.
//Complex properites are simple
public class MyComplextClass{
public List<MyThings> MyThings {get;set;}
public List<FileInfo> MyFiles {get;set;}
public List<DateTime> MyDates {get;set;}
}
I need a little help i am using a class and want to set the properties based on choice on type int,string and datetime here is my code that i wrote but as my constructor will be confused between public string paramValue and public int? paramValue what is the best way to set properties based on choice so only one property can be set a time.Thanks for any suggestion
public class PassData
{
private string _ParamName { get; set; }
private int? _ParamValueInt { get; set; }
private string _ParamValueString { get; set; }
private DateTime? _ParamValueDateTime { get; set; }
public string paramName
{
get { return _ParamName; }
set { _ParamName = value;}
}
public string paramValue
{
get { return _ParamValueString; }
set {_ParamValueString = value; }
}
public int? paramValue
{
get { return _ParamValueInt; }
set { _ParamValueInt = value; }
}
public PassData(string ParamName, int ParamValue)
{
paramName = ParamName;
paramValue = ParamValue;
}
public PassData(string ParamName, string ParamValue)
{
ParamName = ParamName;
ParamValueString = ParamValue;
}
public PassData(string ParamName, DateTime ParamValue)
{
ParamName = ParamName;
ParamValueDateTime = ParamValue;
}
}
Basically, you can't have multiple properties on an object that only differ by type. You have a few options.
1) Create a single property that can hold various types:
private Object _paramValue;
public Object ParamValue
{
get { return _paramValue; }
set {_paramValue= value; }
}
In your setter, you can throw an exception if the value is a type you don't like. You'd also have to upcast the result every time you called the getter, making this solution not ideal. If you want to go this route, I'd suggest making the property an interface, and defining various implementations for the types of data you need.
2) Create a generic class:
public class PassData<T>
{
private T _paramValue;
public T paramValue
{
get { return _paramValue; }
set {_paramValue= value; }
}
}
This has the disadvantage of not being able to change the type after the instance is created. It was unclear if this was a requirement for you.
I like this design as it provides for the possibility of making the constructor for this class private:
public class PassData<T>
{
private PassData(T value)
{
this._paramValue = value;
}
}
If you did this, you can create overloaded static methods to allow the creation of instances:
public static PassData<String> CreateValue(string value)
{
return new PassData<String>(value);
}
public static PassData<Int32> CreateValue(Int32 value)
{
return new PassData<Int32>(value);
}
That way, you can control what types can be created.
Not an answer (in the sense that it does not offer you a way to do what you're trying to do, as Mike Christensen's answer covers it). I just wanted to get more into why what you are trying to do is not working.
Your expectation for it to work is not unreasonable per se, the issue is that c# is not polymorphic on return values. I think some other languages are, C# is not.
i.e. while in c#, you can do:
public void test(int val) {}
public void test(string val) {}
// When you call `test` with either an int or a string,
// the compiler will know which one to call
you CAN'T do:
public int test() {return 1;}
public string test() {return "1";}
// does not compile. The compiler should look at the call
// site and see what you assign the result of "test()" to
// to decide. But there are various edge cases and it was decided
// to leave this out of the language
Now, the get on string paramValue is functionally equivalent to this scenario. You're trying to get the compiler to decide which paramValue to call based on the return value.
Consider the following class:
[DebuggerDisplay("{GetType().Name,nq}: FileName = {FileName,nq}")]
public class FileWrapper
{
public string FileName { get; set; }
public bool IsTempFile { get; set; }
public string TempFileName { get; set; }
}
I would like to add a debugger display based on the IsTempFileName property. I would like to add the string , TempFileName = {TempFileName,nq} when the instance is a temp file. How would I achieve something this?
You can use the conditional operator (?:)
[DebuggerDisplay("{GetType().Name,nq}: FileName = {FileName,nq}{IsTempFile ? \", TempFileName: \" + TempFileName : System.String.Empty,nq}")]
IsTempFile == false
IsTempFile == true
You can use whatever expression is valid.
However, keep in mind that the debugger will evaluate these expressions a lot, so the more complicated you make them, the more you will start to noticed reduced debugging speed (e.g. when stepping through code).
Another major thing to consider is that the expression is evaluated by the debugger for the language using the class.
If both the class and all its potential users are in C#, there is no problem and you can use things like the ternary operator.
However, if your class is also to be used from another language, then:
there's no guarantee the debugger will even use the [DebuggerDisplay] attribute at all,
if it does, there's no guarantee that it will try to evaluate {expression} blocks, and
there's a very good chance that it will fail to evaluate your C# expression if you start doing anything fancy (like using ?:)
The safest thing would be to add a private property to compute the debugger value:
[DebuggerDisplay("{DebugValue,nq}")]
public class FileWrapper {
public string FileName { get; set; }
public bool IsTempFile { get; set; }
public string TempFileName { get; set; }
private string DebugValue {
get {
var text = string.Format("{0}: FileName={1}", this.GetType(), this.FileName);
if (this.IsTempFile)
text += string.Format(", TempFileName={0}", this.TempFileName);
return text;
}
}
}
It's a private property, so it doesn't get in the way of any potential subclasses.
First, upvote "sloth" answer before mine....because they got me going on the right direction.
Second, Here is an article:
https://devblogs.microsoft.com/visualstudio/customize-object-displays-in-the-visual-studio-debugger-your-way/
Below is the name of the article and the author, in case the link above dies in the future.
Customize object displays in the Visual Studio debugger YOUR way
Leslie Richardson
Program Manager, Visual Studio Debugging & Diagnostics
Third, here is a slightly more generic example based on a null or not null child collection:
[System.Diagnostics.DebuggerDisplay("ParentName = '{ParentName}', MyKidsCount='{null == MyKids ? 0 : MyKids.Count}'")]
public class MyParent
{
public string ParentName { get; set; }
public ICollection<MyKid> MyKids { get; set; }
}
You can use it with the Extensions method.
using System;
using System.Linq;
using System.Diagnostics;
using System.ComponentModel;
namespace ConsoleApplicationDebuggerDisplay
{
class Program
{
static void Main(string[] args)
{
MyObject o1 = new MyObject();
MyObject o2 = new MyObject();
o1.Items = new int[] { 1, 2, 3, 4 };
}
}
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class MyObject
{
[DebuggerDisplay("{Items.ToDebuggerDisplay(),nq}")]
public int[] Items { get; set; }
[DebuggerBrowsable(DebuggerBrowsableState.Never), Browsable(false)]
internal string DebuggerDisplay
{
get
{
return string.Format("{{Items={0} ...}}"
, Items.ToDebuggerDisplay()
);
}
}
}
internal static class Extensions
{
public static bool IsNull(this object o)
{
return object.ReferenceEquals(o, null);
}
public static bool IsNotNull(this object o)
{
return !object.ReferenceEquals(o, null);
}
public static string ToDebuggerDisplay<T>(this System.Collections.Generic.IEnumerable<T> items)
{
if (items.IsNull())
return "null";
return string.Format("{{Count={0}}}", items.Count());
}
}
}
Watch
I am working with insurance and have two different policy types - motor and household, represented by two different classes, Motor and Household.
Both have several bits of data in common, so both would inherit from another class called Policy. When a user logs into the app, they could have either a motor or a household policy, so the app needs to display the generic information and the information unique to Motor or Household. To encapsulate all this, i have a response object that has both a Motor member and a Household member, as shown below:
public class Response
{
...
private MotorPolicy _motorPolicy;
private HouseholdPolicy _householdPolicy;
....
}
The code below should demonstrate:
if (response.PolicyType == Enumerations.PolicyType.Motor)
{
lblDescription.Text = response.MotorPolicy.Description;
lblReg.Text = response.MotorPolicy.Reg;
}
else
{
lblDescription.Text = response.HouseholdPolicy.Description;
lblContents.Text = response.HouseholdPolicy.Contents;
}
The MotorPolicy doesn't have Contents property and the HouseholdPolicy doesn't have a Reg property.
But I really want to simply do:
if (response.PolicyType == Enumerations.PolicyType.Motor)
{
lblDescription.Text = response.Policy.Description;
...
}
I have tried using generics, could couldn't find the right solution.
Your response only needs a Policy type, you can then store a MotorPolicy or HouseholdPolicy type into it.
Then your response just needs to check for data type
if (response.Policy is MotorPolicy) ....
Alternatively have an abstract method or a property returning data from an abstract method on the Policy type that is fully inplemented by the child classes and returns reg data or contents data as apporpriate.
Each Policy descendant (now you have two, you might have more in the future, right?) should have their own UI controls which "know" how to deal with the policy information. The same approach can be used for other things, such as a "controller" for policy objects etc.
The response can then be made generic:
public class Response<T> where T: Policy {
...
private T _policy;
....
}
Alternatively, you could have a more generic approach which uses reflection to display the information, but those are usually less "sexy" in their appearance and usability (think of the Property Grid in the VS designer).
public interface IPolicy
{
string Description { get; }
string Reg { get; }
string Contents { get; }
}
public class MotorPolicy : IPolicy
{
public string Description
{
get { return ...; }
}
public string Reg
{
get { return ...; }
}
public string Contents
{
get { return String.Empty; }
}
}
public class HousholdPolicy : IPolicy
{
public string Description
{
get { return ...; }
}
public string Reg
{
get { return String.Empty; }
}
public string Contents
{
get { return ...; }
}
}
public class Response
{
...
private IPolicy _policy;
....
}
Now you don't need an Enumeration to show which type you've implemented, you can just say
lblDescription.Text = response.Policy.Description;
lblReg.Text = response.Policy.Reg;
lblContents.Text = response.Policy.Contents;
Edit: Alternate solution
public interface IPolicy
{
string Description { get; }
}
public interface IHasReg
{
string Reg { get; }
}
public interface IHasContents
{
string Contents { get; }
}
public class MotorPolicy : IPolicy, IHasReg
{
public string Description
{
get { return ...; }
}
public string Reg
{
get { return ...; }
}
}
public class HouseholdPolicy : IPolicy, IHasContents
{
public string Description
{
get { return ...; }
}
public string Contents
{
get { return ...; }
}
}
public class Response
{
...
private IPolicy _policy;
....
}
This leaves you with more code in the calling function
lblDescription.Text = response.Policy.Description;
IHasReg hasReg = response.Policy as IHasReg;
if (hasReg != null) lblReg.Text = hasReg.Reg;
IHasContents hasContents = response.Policy as IHasContents;
if (hasContents != null) lblContents.Text = hasContents.Contents;
but is considerably more extensible than other options presented and complies with your desire to avoid functionality in the implementation which doesn't make sense.
One option is to add a member to Policy that synthesizes all the derived class' relevant properties to provide a summary:
public abstract class Policy {
public string Description { get; set; }
public abstract string Summary { get; }
}
public class MotorPolicy: Policy {
public override string Summary {
get { return this.Description + "\r\n" + this.Reg; }
}
}
public class HouseholdPolicy: Policy {
public override string Summary {
get { return this.Description + "\r\n" + this.Contents; }
}
}
This centralizes the logic and makes the user interface code simple:
label.Description.Text = response.Policy.Summary;
That basic implementation sacrifices the ability to format the subsections separately. You could overcome that by exposing the summary as a collection of strings:
public abstract IEnumerable<string> SummarySections { get; }
If you want to display the derived classes' details in fundamentally different ways, you'll have to embrace the conditional logic in the user interface layer (for example, you might list the household policy's contents in a table, but show a scanned image for the motor policy's registration).
Use the template pattern:
Create a base class called Policy with a virtual abstract get method to determine the description of the policy.
public abstract class Policy
{
protected virtual string GetDescription()
{
return string.Empty()
}
public string Description
{
get
{
return GetDescription();
}
}
}
public MotorPolicy : Policy
{
public override string GetDescription()
{
return ..... ////specific description implementation for MotorPolicy
}
}
public HouseHoldPolicy : Policy
{
public override string GetDescription()
{
return ..... ////specific description implementation for HouseholdPolicy
}
}
public class Response
{
...
private MotorPolicy _motorPolicy;
private HouseholdPolicy _householdPolicy;
private PolicyType _policyType;
....
public Policy Policy
{
get
{
if (_policyType== PolicyType.Motor)
{
return _motorPolicy;
}
if (_policyType== PolicyType.Household)
{
return _householdPolicy;
}
return null;
}
}
}
client code:
if (response.Policy != null)
{
lblDescription.Text = response.Policy.Description;
...
}
Let MotorPolicy and HouseholdPolicy derive from Policy and override the abstract get method from the base and create a specific implementation of it.
In the Response class just get the description.
The simplest solution would be to implement an interface with a description property and a "contents" property, and then in your motor policy class, create a dummy "contents" property which returns "reg".
Can your response contain either a MotorPolicy or a HouseholdPolicy or, can it contain one of each?
If you are dealing with one or the other then create a base type that both classes inherit that defines the common properties. When you output the common properties just cast the Policy as the base type and use that.
My immediate thought is to go for:
public abstract class Response
{
public abstract Policy Policy {get;}//can be used for stuff for dealing with all policies.
public static Response GetResponse(Policy policy)
{//factory method
if(policy is MotorPolicy)
return new MotorResponse((MotorPolicy)policy);
if(policy is HouseholdPolicy)
return new HouseholdResponse((HouseholdPolicy)policy);
throw new ArgumentException("Unexpected policy type");
}
}
public class MotorResponse : Response
{
private readonly MotorPolicy _motorPolicy;
public MotorResponse(MotorPolicy policy)
{
_motorPolicy = policy;
}
protected override Policy Policy
{
get { return _motorPolicy; }
}
// motor specific stuff
}
public class HouseholdResponse : Response
{
private readonly HouseholdPolicy _householdPolicy;
public HouseholdResponse(HouseholdPolicy policy)
{
_householdPolicy = policy;
}
protected override Policy Policy
{
get { return _householdPolicy; }
}
// household specific stuff
}
I would try something like this:
public class Response
{
public Policy SelectedPolicy {get;set;}
//I don't think you need these, but hard to
//say without seeing the rest of the code
...
private MotorPolicy _motorPolicy;
private HouseholdPolicy _householdPolicy;
....
}
then
lblDescription.Text = response.SelectedPolicy.Description;
if (SelectedPolicy is MotorPolicy)
lblReg.Text = ((MotorPolicy)response.SelectedPolicy).Reg;
else if (SelectedPolicy is HouseholdPolicy)
lblContents.Text = ((HouseholdPolicy)response.SelectedPolicy).Contents;
I would not put both Reg and Contents in the base class or interface. If I do what's the purpose of inheritance if all classes look the same? The only benefits I would get would be types, and that's not going to gain me much in this case.
maybe I don't understand the question but I would just use inheritence
define policy as
public class Policy
{
public string Description{ get; set;}
public string Details {get; set;}
}
public class MotorPolicy:Policy
{
public void SetReg(string reg)
{
base.Details = reg;
}
}
public class HousePolicy:Policy
{
public void SetContents(string contents)
{
base.Details = contents;
}
}
and call by
private void Form1_Load(object sender, EventArgs e)
{
MotorPolicy mp = new MotorPolicy();
mp.Description = "Motor";
SetForm(mp);
}
private void SetForm(Policy p)
{
lblDescription.Text = p.Description;
lblDetail.Text = p.Details;
//then if you still need specifics
if (p.GetType() == typeof(MotorPolicy))
{
MotorPolicy mp = p as MotorPolicy;
//continue assigning mp
}
else if (p.GetType() == typeof(HousePolicy))
{
HousePolicy hp = p as HousePolicy;
//continue assigning Hp
}
}
Note I put reg/contents as a field detail as they are both string types. If one was int vs string then they would have to be done separate.
define the Policy interface and implement it in your both the policy classes
Interface IPolicy{
int Reg {get;set;};
string Contents {get;set;};
}
MotorPolicy : Policy,IPolicy {
string IPolicy.Contents
{get;set;};
int IPolicy.Reg
{get;set;};
}
HouseholdPolicy : Policy , IPolicy {
string IPolicy.Contents
{get;set;};
int IPolicy.Reg
{get;set;};
}
Yours is a unique example of "Refactoring condition to Polymorphism" [Fowler].
And then your method should accept the proper object and do as below:
public void Update(IPolicy policy)
{
lblDescription.Text = policy.Description;
lblReg.Text = .Reg;
}
Well, I dislike abstract classes so I went with an interface for Policy
public interface IPolicy
{
string Description { get; set;}
void Display();
}
Then we inherit from it to create MotorPolicy
public class MotorPolicy : IPolicy
{
public string Description { get; set; }
public string Reg { get; set; }
public void Display()
{
Console.WriteLine(string.Format("Description: {0}", Description));
Console.WriteLine(string.Format("Reg: {0}", Reg));
}
}
Then for response I changed the Policy to a List in the off chance that you can have both or either. Now we've offloaded the handling of displaying the data to the specific policy itself.
public class Response
{
public List<IPolicy> Policies { get; set; }
public void Display()
{
Policies.ForEach(p => p.Display());
}
public void Display(Type t)
{
var policy = (from p in Policies
where p.GetType() == t
select p).FirstOrDefault();
policy.Display();
}
}
This could easily be changed to not use the List and we can get rid of the overloaded Display.