I have following two classes:
public class A : System.Web.UI.WebControls.Button
{
public virtual string X
{
get
{
object obj = ViewState["X"];
if (obj != null) return (string)obj;
return null;
}
set
{
ViewState["X"] = value;
}
}
protected override void OnLoad(EventArgs e)
{
X=2;
}
}
and
public class B : System.Web.UI.WebControls.TextBox {
public virtual string X
{
get
{
object obj = ViewState["X"];
if (obj != null) return (string)obj;
return null;
}
set
{
ViewState["X"] = value;
}
}
protected override void OnLoad(EventArgs e)
{
X=2;
}
}
As you must be seeing the class A and B have exactly the same code , my question is how can I make a common class for it and use these two classes.
The replacement for inheritance is composition.
Define a new class and insert invocations of it's methods in A and B. In this example it seems too complicated, but you will avoid code duplication if you decide to replace ViewState["X"]
class C {
public virtual string X
{
get
{
return ViewState["X"];
}
set
{
ViewState["X"] = value;
}
}
public SetX()
{
X=2;
}
}
Extension methods is a good alternative too.
Related
I have the following setup:
public class Child<T>: BaseClass
{
public T Value;
}
public class IntChild: Child<int> { }
public class BoolChild: Child<bool> { }
public class FloatChild: Child<float> { }
public class MyProgram
{
public BaseClass Source;
public void SetValue(object val)
{
// I want to do something like the following
// ((Child) Source).Value = (val.GetType()) val;
// Instead, I have to do it like this
string temp = val.ToString();
switch (Source.GetType())
{
case "IntChild":
((IntChild) Source).Value = int.Parse(val.ToString());
break;
case "BoolChild":
((BoolChild) Source).Value = bool.Parse(val.ToString());
break;
case "FloatChild":
((FloatChild) Source).Value = float.Parse(val.ToString());
break;
}
}
}
I cannot modify the BaseClass (I could only overwrite ToString()).
How can I replace the switch with a simpler line of code? I want to do something like the following
((Child) Source).Value = (val.GetType()) val;
,instead of the switch. Is this even possible?
You should use the visitor pattern:
public abstract class BaseClassWithVisitor : BaseClass {
void AcceptVisitor(BaseClassVisitor visitor);
}
This means Child<T> become abstract too.
Make all Child<T> children class implements BaseClassWithVisitor.AcceptVisitor() method, so they are not abstract:
public class IntChild : Child<int> {
...
/// This method should be implemented in all Child<T> descendant classes
public override void AcceptVisitor(BaseClassVisitor visitor) { visitor.Visit(this); }
...
}
Then define the BaseClassVisitor interface :
public interface BaseClassVisitor {
void Visit(IntChild intChild);
void Visit(...); // all the other possible types
...
}
Then eventually create an implementation of the BaseClassVisitor that will do the operation you wanted:
public class SetValueVisitor : BaseClassVisitor {
void Visit(IntChild intChild) { intChild.Value = 1; }
void Visit(BoolChild boolChild) { boolChild.Value = false; }
...
}
Here is a complete example to make things clearer:
using System;
using System.Globalization;
namespace Visitor
{
class BaseClass
{
}
abstract class BaseClassWithVisitor : BaseClass
{
public abstract void AcceptVisitor(Visitor visitor);
}
abstract class Child<T> : BaseClassWithVisitor
{
public T Value;
}
class IntChild : Child<int>
{
public override void AcceptVisitor(Visitor visitor)
{
visitor.Visit(this);
}
}
class FloatChild : Child<float>
{
public override void AcceptVisitor(Visitor visitor)
{
visitor.Visit(this);
}
}
class StringChild : Child<string>
{
public override void AcceptVisitor(Visitor visitor)
{
visitor.Visit(this);
}
}
class Visitor
{
public object Value;
public void Visit(IntChild intChild)
{
intChild.Value = int.Parse(Value.ToString());
}
public void Visit(FloatChild floatChild)
{
floatChild.Value = float.Parse(Value.ToString(), CultureInfo.InvariantCulture);
}
public void Visit(StringChild stringChild)
{
stringChild.Value = Value.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var visitor = new Visitor { Value = "12345" };
var intChild = new IntChild();
intChild.AcceptVisitor(visitor);
visitor = new Visitor { Value = "1.2345" };
var floatChild = new FloatChild();
floatChild.AcceptVisitor(visitor);
visitor = new Visitor { Value = "Hello World" };
var stringChild = new StringChild();
stringChild.AcceptVisitor(visitor);
Console.WriteLine("intChild.Value = {0}", intChild.Value);
Console.WriteLine("floatChild.Value = {0}", floatChild.Value);
Console.WriteLine("stringChild.Value = {0}", stringChild.Value);
}
}
}
This will output:
intChild.Value = 12345
floatChild.Value = 1,2345
stringChild.Value = Hello World
You can do it via reflection without classes modifying at all:
public void SetValue(object val)
{
Source.GetType().GetProperty("Value").SetValue(Source, value);
}
Small variation of answer already provided by Slava Utesinov
// Only set value if implementation of Child<>.
// If any other derived class of BaseClass with value field, then dont set
if(source.GetType().BaseType != null
&& source.GetType().BaseType.IsGenericType
&& source.GetType().BaseType.GetGenericTypeDefinition() == typeof(Child<>))
{
Console.WriteLine("Is implementation of Child<>");
source.GetType().GetField("Value").SetValue(source, val);
}
else
{
Console.WriteLine("Not implementation of Child<>");
}
One option to consider:
public void SetValue(object val)
{
dynamic dynamicSource = Source;
dynamicSource.Value = val;
}
It is a similar approach to the reflection based approaches, but a little more concise.
We are using HttpSessionStateBase to store messages in a set up similar to this working example:
public class HttpSessionMessageDisplayFetch : IMessageDisplayFetch
{
protected HttpSessionStateBase _session;
private IList<ICoreMessage> messages
{
get
{
if (_session[EchoCoreConstants.MESSAGE_KEY] == null)
_session[EchoCoreConstants.MESSAGE_KEY] = new List<ICoreMessage>();
return _session[EchoCoreConstants.MESSAGE_KEY] as IList<ICoreMessage>;
}
}
public HttpSessionMessageDisplayFetch()
{
if (HttpContext.Current != null)
_session = new HttpSessionStateWrapper(HttpContext.Current.Session);
}
public void AddMessage(ICoreMessage message)
{
if (message != null)
messages.Add(message);
}
public IEnumerable<IResultPresentation> FlushMessagesAsPresentations(IResultFormatter formatter)
{
var mToReturn = messages.Select(m => m.GetPresentation(formatter)).ToList();
messages.Clear();
return mToReturn;
}
}
When we pass in a QualityExplicitlySetMessage (which inherits from ICoreMessage, see below) it is saved correctly to messages.
This is how the object looks after being inserted into the messages list, at the end of AddMessage(ICoreMessage message) above.
But when we come to access it after changing controllers the inherited member's properties are null, which causes a variety of null reference exceptions.
This is how the object now looks after we call FlushMessagesAsPresentations. I've commented out var mToReturn... as this tries to access one of these null ref properties.
I'd like to ask the following:
Why is the HttpSessionStateBase failing to capture these values taken
by the inherited type?
Is this an issue in saving to the HttpSession or in retrieving?
Is this anything to do with, as I suspect, inheritance?
Or is the fact I'm potentially calling a new controller that dependency injects the HttpSessionMessageDisplayFetch causing an issue?
I'm a first-time poster so please let me know if I'm making any kind of faux pas - Super keen to learn! Any input is very welcome.
Some potentially useful code snippets:
QualityExplicitlySetMessage
public class QualityExplicitlySetMessage : QualityChangeMessage
{
public QualityExplicitlySetMessage(IQPossession before, IQPossession after, IQEffect qEffect)
: base(before, after, qEffect)
{
IsSetToExactly = true;
}
}
QualityChangeMessage - Working example
public abstract class QualityChangeMessage : CoreMessage, IQualityChangeMessage
{
protected PossessionChange Change;
public PossessionChange GetPossessionChange()
{
return Change;
}
protected QualityChangeMessage(IQPossession before, IQPossession after, IQEffect qEffect)
{
Change = new PossessionChange(before, after, qEffect);
StoreQualityInfo(qEffect.AssociatedQuality);
}
public override IResultPresentation GetPresentation(IResultFormatter formatter)
{
return formatter.GetQualityResult(this);
}
#region IQualityChangeMessage implementation
public int LevelBefore
{
get { return Change.Before.Level; }
}
//... And so on with values dependent on the Change property.
}
CoreMessage - Working example
public abstract class CoreMessage : ICoreMessage
{
public string MessageType
{
get { return GetType().ToString(); }
}
public string ImageTooltip
{
get { return _imagetooltip; }
set { _imagetooltip = value; }
}
public string Image
{
get { return _image; }
set { _image = value; }
}
public int? RelevantQualityId { get; set; }
protected void StoreQualityInfo(Quality q)
{
PyramidNumberIncreaseLimit = q.PyramidNumberIncreaseLimit;
RelevantQualityId = q.Id;
RelevantQualityName = q.Name;
ImageTooltip = "<strong>" + q.Name + "</strong><br/>" + q.Description + "<br>" +
q.EnhancementsDescription;
Image = q.Image;
}
public virtual IResultPresentation GetPresentation(IResultFormatter formatter)
{
return formatter.GetResult(this);
}
}
UserController - Working example.
public partial class UserController : Controller
{
private readonly IMessageDisplayFetch _messageDisplayFetch;
public UserController(IMessageDisplayFetch messageDisplayFetch)
{
_messageDisplayFetch = messageDisplayFetch;
}
public virtual ActionResult MessagesForStoryletWindow()
{
var activeChar = _us.CurrentCharacter();
IEnumerable<IResultPresentation> messages;
messages = _messageDisplayFetch.FlushMessagesAsPresentations(_storyFormatter);
var vd = new MessagesViewData(messages)
{
Character = new CharacterViewData(activeChar),
};
return View(Views.Messages, vd);
}
}
I need to implement automatic UI Tests for a Delphi Application with Visual Studio Coded UI Tests. I have already implemented the IAccessible Interface to my Delphi-Contols. It works fine and i get the AccessibleName from the Control.
Then i implemented an extension for visual studio. In this extension i have my own PropertyProvider-, ExtensionPackage- and WinControl-Class.
PropertyProvider:
namespace CUITExtension
{
public class AccessibleNamePropertyProvider : UITestPropertyProvider
{
private static Dictionary<string, UITestPropertyDescriptor> accessibleNamePropertyMap = null;
private static Dictionary<string, UITestPropertyDescriptor> AccessibleNamePropertyMap
{
get
{
if (accessibleNamePropertyMap == null)
{
UITestPropertyAttributes read = UITestPropertyAttributes.Readable
| UITestPropertyAttributes.DoNotGenerateProperties;
accessibleNamePropertyMap = new Dictionary<string, UITestPropertyDescriptor>
(StringComparer.OrdinalIgnoreCase);
accessibleNamePropertyMap.Add("AccessibleName", new UITestPropertyDescriptor(typeof(string), read));
}
return accessibleNamePropertyMap;
}
}
public override UITestPropertyDescriptor GetPropertyDescriptor(UITestControl uiTestControl, string propertyName)
{
return AccessibleNamePropertyMap[propertyName];
}
public override ICollection<string> GetPropertyNames(UITestControl uiTestControl)
{
if (uiTestControl.ControlType.NameEquals("Custom"))
{
// the keys of the property map are the collection of property names
return AccessibleNamePropertyMap.Keys;
}
throw new NotSupportedException();
}
public override object GetPropertyValue(UITestControl uiTestControl, string propertyName)
{
if (String.Equals(propertyName, "AccessibleName", StringComparison.OrdinalIgnoreCase))
{
object[] native = uiTestControl.NativeElement as object[];
IAccessible acc = native[0] as IAccessible;
return acc.accName;
}
throw new NotSupportedException();
}
public override int GetControlSupportLevel(UITestControl uiTestControl)
{
if (string.Equals(uiTestControl.TechnologyName, "MSAA",
StringComparison.OrdinalIgnoreCase) &&
uiTestControl.ControlType.NameEquals("Custom"))
{
return (int)ControlSupport.ControlSpecificSupport;
}
// This is not my control, so return NoSupport
return (int)ControlSupport.NoSupport;
}
public override string[] GetPredefinedSearchProperties(Type specializedClass)
{
return null;
}
public override string GetPropertyForAction(UITestControl uiTestControl, UITestAction action)
{
return null;
}
public override string[] GetPropertyForControlState(UITestControl uiTestControl, ControlStates uiState, out bool[] stateValues)
{
stateValues = null;
return null;
}
public override Type GetPropertyNamesClassType(UITestControl uiTestControl)
{
if (uiTestControl.ControlType.NameEquals("Custom"))
return typeof(AccessibleControl.PropertyNames);
return null;
}
public override Type GetSpecializedClass(UITestControl uiTestControl)
{
if (uiTestControl.ControlType.NameEquals("Custom"))
return typeof(AccessibleControl);
return null;
}
public override void SetPropertyValue(UITestControl uiTestControl, string propertyName, object value)
{
return;
}
}
}
ExtensionPackage:
[assembly: Microsoft.VisualStudio.TestTools.UITest.Extension.UITestExtensionPackage(
"AccessibleNameExtensionPackage",
typeof(CUITExtension.AccessibleNameExtensionPackage))]
namespace CUITExtension
{
class AccessibleNameExtensionPackage : UITestExtensionPackage
{
public override string PackageDescription
{
get { return "Supports coded UI testing by using the AccessibleName"; }
}
public override string PackageName
{
get { return "AccessibleName Extension Package"; }
}
public override string PackageVendor
{
get { return "Microsoft (sample)"; }
}
public override Version PackageVersion
{
get { return new Version(1, 0); }
}
public override Version VSVersion
{
get { return new Version(14, 0); }
}
public override void Dispose() { }
public override object GetService(Type serviceType)
{
if (serviceType == typeof(UITestPropertyProvider))
{
if (propertyProvider == null)
{
propertyProvider = new AccessibleNamePropertyProvider();
}
return propertyProvider;
}
return null;
}
private UITestPropertyProvider propertyProvider = null;
}
}
WinControl:
namespace CUITExtension
{
public class AccessibleControl : WinControl
{
public AccessibleControl(UITestControl c) : base(c)
{
TechnologyName = "MSAA";
SearchProperties.Add(UITestControl.PropertyNames.ControlType, "Custom");
}
public virtual string AccessibleName
{
get
{
return (string)GetProperty("AccessibleName");
}
}
}
}
Now the Coded UI Test Builder is showing the AccessibleName and is also generating AccessibleName as a SearchProperty.
UIMap:
public AccessibleControl UIItemCustom
{
get
{
if ((this.mUIItemCustom == null))
{
this.mUIItemCustom = new AccessibleControl(this);
#region Search Criteria
this.mUIItemCustom.SearchProperties["AccessibleName"] = "UniqueName1";
this.mUIItemCustom.SearchProperties[WinControl.PropertyNames.ClassName] = "TEdit";
this.mUIItemCustom.WindowTitles.Add("Title");
#endregion
}
return this.mUIItemCustom;
}
}
*I have changed the Searchproperties here (only for the post, i didnt changed the generated code)
Now when I start the test, I get an exception that says that AccessibleName is not an valid searchproperty. I got this exception before, when i havent implemented the extension yet. But I thougth by implementing the propertyprovider AccessibleName should be a valid searchproperty now.
I tried to debug it, but it seems like by searching the Control it doesnt use the propertyprovider and i have no idea why?
I hope you can help me and if you need more information just ask.
Paul
I got the problem with the valid searchproperty to work.
I overrode the GetValidSearchProperties method from WinControl.
protected override Dictionary<string, bool> GetValidSearchProperties()
{
Dictionary<string, bool> searchProperties = base.GetValidSearchProperties();
if (!searchProperties.ContainsKey("AccessibleName"))
searchProperties.Add("AccessibleName", true);
return searchProperties;
}
I have an <asp:Label> I wish to populate depending on the Generic object that I pass to it.
At the moment I have the following code:-
private void PopulateEnglishQuestion(int questionId)
{
ReportQuestion reportQuestion = questionsBll.GetReportQuestions().Where(x=> x.ReportQuestionId == questionId).FirstOrDefault();
PopulateLabels(reportQuestion);
}
private void PopulateTranslatedQuesiton(int questionId)
{
ReportQuestionTranslation reportQuestionTranslation = questionsBll.GetReportQuestionsTranslation().Where(x => x.QuestionId == questionId).FirstOrDefault();
PopulateLabels(reportQuestionTranslation);
}
private void PopulateLabels<T>(T item)
{
lblQuestionTitle.Text = typeof (T) == typeof (ReportQuestion)
? ((ReportQuestion) (item)).ReportQuestionTitle
: ((ReportQuestionTranslation) (item)).ReportQuestionTitleTrans;
}
How can I get the method PopulateLabels to work properly?
You should use an interface both ReportQuestion and ReportQuestionTranslation implement:
interface IQuestion
{
string TitleText;
}
Then, use the following code:
public void PopulateLabels(IQuestion item)
{
lblQuestionTitle.Text = item.TitleText;
}
Use an interface.
public interface IQuestion
{
string Title { get; }
}
public class ReportQuestion : IQuestion
{
public string Title { get { return ReportQuestionTitle; } }
}
public class ReportQuestionTranslation: IQuestion
{
public string Title { get { return ReportQuestionTitleTrans; } }
}
private void PopulateLabels(IQuestion item)
{
lblQuestionTitle.Text = item.Title;
}
Or use method overloading:
public void PopulateTitle(ReportQuestion question)
{
lblQuestionTitle.Text = question.ReportQuestionTitle;
}
public void PopulateTitle(ReportQuestionTranslation question)
{
lblQuestionTitle.Text = question.ReportQuestionTitleTrans;
}
Unrecommended:
public class QuestionTitleFormatter
{
public string GetTitle(object question)
{
if(question is ReportQuestion)
return ((ReportQuestion)question).ReportQuestionTitle;
if(question is ReportQuestionTranslation)
return ((ReportQuestionTranslation)question).ReportQuestionTitleTrans;
throw new NotImplementedException(string.Format("{0} is not supported", questionType.Name);
}
}
public void PopulateTitle(object question)
{
var formatter = new QuestionTitleFormatter();
lblQuestionTitle.Text = formatter.GetTitle(question);
}
The ToString() approach would be something like this:
class ReportQuestion {
public override string ToString() { return ReportQuestionTitle; }
...
}
class ReportQuestionTranslation{
public override string ToString() { return ReportQuestionTitleTrans; }
...
}
assuming that I answered my own question correctly in the comment above asking where the string will come from.
You could just override ToString() on those objects and not worry about any transformations or types in PopulateLabel.
I've got problem using generics. I'm creating an interface called IProblem, where each problem has results (answers) and a result (if it is correct)
public interface IProblem<T>
{
ushort ResultCount { get; }
T[] Results { get; }
bool IsCorrect();
}
public abstract class ProblemBase<T> : IProblem<T>
{
private T[] _results;
private ushort? _resultCount;
public ushort ResultCount
{
get
{
if (_resultCount == null) throw new ArgumentNullException("_resultCount");
return (ushort)_resultCount;
}
protected set
{
if (_resultCount != value)
_resultCount = value;
}
}
public T[] Results
{
get
{
if (_results == null)
_results = new T[ResultCount];
return _results;
}
}
public abstract bool IsCorrect();
}
This is an example where I create an arithmetic problem, called ProblemA. T is decimal because the array datatype should be decimal (anothers problems maybe might have string, or int)
public class ProblemA: ProblemBase<decimal>
{
private decimal _number1;
private decimal _number2;
private Operators _operator;
public decimal Number1
{
get { return _number1; }
set { _number1 = value; }
}
public decimal Number2
{
get { return _number2; }
set { _number2 = value; }
}
public Operators Operator
{
get { return _operator; }
set { _operator = value; }
}
public decimal Result
{
get { return Results[0]; }
set { Results[0] = value; }
}
public ProblemA()
{
this.ResultCount = 1;
}
public override bool IsCorrect()
{
bool result;
switch (_operator)
{
case Operators.Addition:
result = this.Result == (this.Number1 + this.Number2);
break;
case Operators.Subtract:
result = this.Result == (this.Number1 - this.Number2);
break;
case Operators.Multiplication:
result = this.Result == (this.Number1 * this.Number2);
break;
case Operators.Division:
result = this.Result == (this.Number1 / this.Number2);
break;
default:
throw new ArgumentException("_operator");
}
return result;
}
}
I'm using MVVM, so I'd like to have a ViewModel for each problem where contains ProblemBase<T> as property, but how it's a generic, I guess it will be a problem if a put in IProblemViewModel as generic.
public interface IProblemViewModel : IViewModel
{
ProblemBase<T> Problem { get; set; }
}
I said this because later a plan to use a ObservableCollection<IProblemViewModel>, so I'm not sure if there's no problem if I write IProblemViewModel or IProblemViewModel<T>.
Thanks in advance.
Maybe I haven't understood this perfectly, but is this what you are after?
ObservableCollection<IProblemViewModel<object>> collection = new ObservableCollection<IProblemViewModel<object>>
{
new ProblemViewModel<DerivedResult>(),
new ProblemViewModel<OtherResult>()
};
This can be achieved by declaring the generic argument as covariant.
You could also change the collection to
ObservableCollection<IProblem<BaseType>>
and just have it accept a specific result chain. In this example, DerivedResult and OtherResult must then inherit from BaseType to fit into the collection.
The big caveat is that primitive types don't fit into this hierarchy, in any way. You will have to wrap them in IProblem<IntResult> and so on.
Of course, you could implement a simple carrier, for example Boxer which would box any value type instead of implementing one for each type.
One last caveat: It's not possible to have a 'set' property on a covariant type, so IProblemViewModel can only support get.
A complete, compilable example:
class Program
{
public interface IProblem<out T>
{
ushort ResultCount { get; }
T[] Results { get; }
bool IsCorrect();
}
public class ProblemBase<T> : IProblem<T>
{
private T[] _results;
private ushort? _resultCount;
public ushort ResultCount
{
get
{
if (_resultCount == null) throw new ArgumentNullException("_resultCount");
return (ushort)_resultCount;
}
protected set
{
if (_resultCount != value)
_resultCount = value;
}
}
public T[] Results
{
get
{
if (_results == null)
_results = new T[ResultCount];
return _results;
}
}
public bool IsCorrect()
{
return true;
}
}
public interface IProblemViewModel<out T>
{
IProblem<T> Problem { get; }
}
public class BaseResult
{
}
public class DerivedResult : BaseResult
{
}
public class OtherResult : BaseResult
{
}
public class ProblemViewModel<T> : IProblemViewModel<T>
{
public IProblem<T> Problem
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
static void Main(string[] args)
{
ObservableCollection<IProblemViewModel<object>> collection = new ObservableCollection<IProblemViewModel<object>>
{
new ProblemViewModel<DerivedResult>(),
new ProblemViewModel<OtherResult>()
//, new ProblemViewModel<int>() // This is not possible, does not compile.
};
}
}
Your view model interface could be defined like this:
public interface IProblemViewModel<T> : IViewModel
{
//No reason to use the base here instead of the interface
IProblem<T> Problem { get; set; }
}
I'm not sure if you are planning on binding the Problem to an interface in WPF or Silverlight, but if you are make sure that Problem also implements INotifyPropertyChanged. Binding to non Dependency Properties on objects that don't implement INotifyPropertyChanged causes the a memory leak where the object will never be released. You can find more info on the leak here: http://support.microsoft.com/kb/938416
EDIT: Added answer to comment.
You are correct that having IProblemViewModel<T> would stop you using it in an ObservableCollection if you intend to show more than one type of <T>. However since when you are binding it doesn't really matter what the objects type is when you bind to it why not just make the collection an ObservableCollection<IViewModel>?