CHyperlink has:
SetURL
SetTooltip
But it does not seem to have Get equivalents?
This class is derived from CMFCLinkCtrl.
How do we implement these?
GetURL
I delved into the source code for CMFCLinkCtrl::SetURL:
void CMFCLinkCtrl::SetURL(LPCTSTR lpszURL)
{
if (lpszURL == NULL)
{
m_strURL.Empty();
}
else
{
m_strURL = lpszURL;
}
}
All I had to do was add a public method to the class I derived from CHyperlink to return the value of m_strURL:
CString GetURL()
{
return m_strURL;
}
GetToolTip
The CMFCLinkCtrl is derived from CMFCButton which has a GetToolTipCtrl method. This returns a reference to the underlying tooltip control. As a result, we can do this to get the tooltip text:
CString GetToolTip()
{
CString strToolTip;
GetToolTipCtrl().GetText(strToolTip, this);
return strToolTip;
}
Related
Driver code
//---------------- Main.hx ------------------------------------------------------------------
import core.reflection.ReflectionTools;
import core.SomeClass;
class Main{
public static function main(){
var s = new SomeClass();
ReflectionTools.info(s);
}
}
The macro
//---------------- ReflectionTools.hx -----------------------------------------------------
class RelectionTools {
public static macro function info(obj:Expr):Expr{
var pos = Context.currentPos();
var block = [];
var result:Dynamic;
var type:Type=Context.typeof(obj);
result=(switch(type){
case TInst(t, params):new RelectionClass(t, params);
case TEnum(t, params):new ReflectionEnum(t, params);
case TDynamic(t):new ReflectionDynamic(t);
case TFun(args, ret):new ReflectionFunction(args, ret);
case TMono(t):new ReflectionMonomorph(t);
case TLazy(f):new ReflectionLazy(f);
case TAbstract(t, params):new ReflectionAbstract(t, params);
case TType(t, params):new ReflectionTypeDefinition(t, params);
case TAnonymous(a):new ReflectionAnonymousStructure(a);
});
return $v{result};
}
}
Haxe Compiler:
Expected Expr but got core.reflection.RelectionClass (see dump/decoding_error.txt for details)
It is not a build macro (which allows returning class instances) but it is an expression macro. The best way to mimic class functionality is with abstracts.
/* Solution Description
1. a custom Json abstract with underlying type {} and with implicit
casts to underlying type. See Json.hx
2. abstracts which reflect possible Type enums with underlying custom
Json abstract and forwards. See example ReflectionPrimitive.hx
and mimic inheritance by underlying types as superclass
see example ReflectionFunction.hx
3. uses same instantiation code as original class instantiation
but now they are abstracts (see PROBLEM(The macro). Solved! */
Step 1.a custom Json abstract with underlying type {} and with implicit casts to
underlying type.
// ---------------- Json.hx ----------------------------------------------
package core.ds.json;
import haxe.Serializer;
import haxe.Unserializer;
import haxe.Json as J;
abstract Json({}) from ({}) to ({}) {
public inline function new(?data:{}){
this=data;
if(this==null){
this={};
}
}
#:arrayAccess
public inline function get(key:String):Dynamic{
if(exists(key)){
return Reflect.field(this,key);
}
return null;
}
#:arrayAccess
public inline function set(key:String, value:Dynamic):Dynamic{
Reflect.setField(this, key, value);
return value;
}
public inline function isEmpty(key:String):Bool{
return !isSet(key) || (exists(key) && ( get(key)=="" || get(key)==''|| get(key)==null || get(key)==0 ));
}
public inline function isSet(key:String):Bool{
return exists(key) && get(key)!=null;
}
public inline function exists(key:String):Bool {
return Reflect.hasField(this, key);
}
#:to
public inline function toMap():Map<String, Dynamic>{
var result:Map<String, Dynamic>=new Map<String, Dynamic>();
var fields:Array<String>=Reflect.fields(this);
for (f in fields){
result.set(f, Reflect.field(this, f));
}
return result;
}
#:to
public inline function toJsonString():String{
return J.stringify(this,null," ");
}
public inline function values():Array<Dynamic>{
var result:Array<Dynamic>=[];
var keys:Array<String>=keys();
for(k in keys){
result.push(Reflect.field(this,k));
}
return result;
}
public inline function keys():Array<String>{
return Reflect.fields(this);
}
public inline function clone():Json{
return Unserializer.run(Serializer.run(this));
}
public var length(get,never):Int;
private inline function get_length():Int{
return keys().length;
}
public inline function keyValueIterator():KeyValueIterator<String, Dynamic>{
return toMap().keyValueIterator();
}
#:from
public static function fromJsonString(json:String):Json{
return J.parse(json);
}
#:from
public static function fromMap(map:Map<String, Dynamic>):Json{
var result={};
for (k=>v in map){
Reflect.setField(result, k, v);
}
return result;
}
}
Step 2. abstracts which reflect possible Type enums with underlying custom Json abstract and forwards. See example ReflectionPrimitive.hx and mimic inheritance by underlying types as superclass see example ReflectionFunction.hx
//---------------- ReflectionPrimitive.hx ----------------------------------------------
#:forward()
abstract ReflectionPrimitive(core.ds.json.Json) from core.ds.json.Json to core.ds.json.Json{
public inline function new(nameType:String){
this=new core.ds.json.Json({data:new core.ds.json.Json(), info:new core.ds.json.Json({nameType:nameType})});
}
public var data(get, set):core.ds.json.Json;
public var info(get, set):core.ds.json.Json;
private function get_data():core.ds.json.Json {
return this["data"];
}
private function set_data(value:core.ds.json.Json):core.ds.json.Json {
this["data"]=value;
return this;
}
private function get_info():core.ds.json.Json {
return this["info"];
}
private function set_info(value:core.ds.json.Json):core.ds.json.Json {
this["info"]=value;
return this;
}
}
Mimmicking inheritance
//---------------- ReflectionFunction.hx ----------------------------------------------
#:forward(data, info, get, isEmpty, isSet, exists, toMap, toJsonString, values, keys, clone, length, keyValueIterator, fromJsonString, fromMap)
abstract ReflectionFunction(ReflectionPrimitive) from ReflectionPrimitive to ReflectionPrimitive{
public inline function new(args:Array<{t:Type, opt:Bool, name:String}>, ret:Type){
this=new ReflectionPrimitive(NameType.FUNCTION);
var newArgs=new Array<core.ds.json.Json>();
for(a in args){
newArgs.push(new core.ds.json.Json(a));
}
this.data=this.data.set("args",newArgs).set("ret", ret);
}
public var args(get, never):Array<core.ds.json.Json>;
public var ret(get,never):Type;
private function get_args():Array<core.ds.json.Json>{
return this.data.get("args");
}
private function get_ret():Type{
return this.data.get("ret");
}
}
Leave the macro untouched it will work now.
Macro is a compile time feature, not runtime feature, you can't return class instance. Instead, you have to return expression which creates a new instance (I don't have your classes, so I use here my class)
var type=Context.typeof(obj);
return (switch(type){
case TInst(t, params):macro new MyClass();//RelectionClass(t, params);
case TEnum(t, params):macro new MyClass();//ReflectionEnum(t, params);
case TDynamic(t):macro new MyClass();//ReflectionDynamic(t);
case TFun(args, ret):macro new MyClass();//ReflectionFunction(args, ret);
case TMono(t):macro new MyClass();//ReflectionMonomorph(t);
case TLazy(f):macro new MyClass();//ReflectionLazy(f);
case TAbstract(t, params):macro new MyClass();//ReflectionAbstract(t, params);
case TType(t, params):macro new MyClass();//ReflectionTypeDefinition(t, params);
case TAnonymous(a):macro new MyClass();//ReflectionAnonymousStructure(a);
});
return macro null;
I am relatively new to C#, maybe you could help me with this.
I got a couple of methods callServiceXY(param1, param2, ...) that call a certain service. For many reasons these service calls can go wrong (and I don't really care for the reason in the end). So basically I need to always wrap them with something like this - to have them execute again if something goes wrong:
var i = 3;
while(i>0)
try{
call...()
} catch{
i--;
}
i=0;
}
I'd rather write this code only once. Could I somehow have a method like tryXtimes(int x, callService()) that allows me to execute an undefined or anonymous method? (I have Javascript in mind where this is possible...)?
Yes this is possible. C# 3.5 added support for Action and Func<T> types. An Action won't return any value, a Func will always return a value.
You have several different versions that also accept a number of parameters. The following Console Applications describes how you could do this:
using System;
namespace Stackoverflow
{
class Service
{
public int MyMethod() { return 42; }
public void MyMethod(string param1, bool param2) { }
public int MyMethod(object paramY) { return 42; }
}
class Program
{
static void ExecuteWithRetry(Action action)
{
try
{
action();
}
catch
{
action();
}
}
static T ExecuteWithRetry<T>(Func<T> function)
{
try
{
return function();
}
catch
{
return function();
}
}
static void Main(string[] args)
{
Service s = new Service();
ExecuteWithRetry(() => s.MyMethod("a", true));
int a = ExecuteWithRetry(() => s.MyMethod(1));
int b = ExecuteWithRetry(() => s.MyMethod(true));
}
}
}
As you can see, there are two overloads for ExecuteWithRetry. One returning void, one returning a type. You can call ExecuteWithRetry by passing an Action or a Func.
--> Edit: Awesome! Just a little extra code to complete the example:
With anonymous function/method:
ExecuteWithRetry(() =>
{
logger.Debug("test");
});
And with more parameters (action, int)
Method header:
public static void ExecuteWithRetryX(Action a, int x)
Method call:
ExecuteWithRetryX(() => { logger.Debug("test"); }, 2);
I would use the strategy/factory pattern(s) for this. This answer https://stackoverflow.com/a/13641801/626442 gives and example of the use of the strategy/factory pattern with links. The question at the above link will give you another type of example where this pattern can be adopted.
There are great examples of these design patterns here and the following are detailed intros to the Strategy pattern and the Factory pattern. The former of the last two links also shows you how to combine the two to do something like what you require.
I hope this helps.
Try following
void CallServiceXY(params object []objects)
{
Console.WriteLine("a");
throw new Exception("");
}
void Retry(int maxRetryCount, Action<object[]> action, params object[] obj)
{
int retryCount = 1;
while ( retryCount <= maxRetryCount)
{
try
{
action(obj);
return;
}
catch
{
retryCount++;
}
}
}
void Main()
{
Retry(2,CallServiceXY);
Retry(2,CallServiceXY,"");
Retry(2,CallServiceXY,"","");
}
Demo here
Trick is Action<object[]> that accepts object array and return void and params keyword in Retry method.
To return non void value, Change Action<object[]> to Func<T, object[]>.
I have a state machine that needs to call a different method on each object from a List of objects depending on the state I'm in. Basically I'm trying to refactor the code that has a loop in each case statement of my state machine so that it looks like the code below. However I cannot seem to figure out how to pass the relevant method to my refactored function (not to mention I then don't know how to call it on each item)
Any help would be appreciated.
Here's the example code:
public class MyOtherType
{
public bool Method1()
{ return false; }
public bool Method2()
{ return false; }
public bool Method3()
{ return false; }
public bool Method4()
{ return false; }
}
public class MyType
{
public enum MyState
{
DoSomething1,
DoSomething2,
DoSomething3,
DoSomething4
}
private MyState State = MyState.DoSomething1;
List<MyOtherType> MyListOfObjects = new List<MyOtherType>() { new MyOtherType(), new MyOtherType() };
private void StateMachine()
{
switch (State)
{
case MyState.DoSomething1:
//How do I pass this in? Do I need to set it up differnetly?
Process(() => MyOtherType.Method1());
break;
case MyState.DoSomething2:
Process(() => MyOtherType.Method2);
break;
case MyState.DoSomething3:
Process(() => MyOtherType.Method3);
break;
case MyState.DoSomething4:
Process(() => MyOtherType.Method4);
break;
}
}
private void Process(Func<bool> method)
{
foreach (MyOtherType item in MyListOfObjects)
{
//How do I call the method on each item?
if (item.method())
{
//Do something
}
}
}
}
I would suggest to get rid of such switch blocks and decouple each specific method from a state by introducing flexible map of strategy per state so it could be easily changed or even injected:
IDictionary<MyState, Func<bool>> strategyMap;
1) Fill it in
// if idea is to access methods without instance of MyOtherType -
// make all methods and class itself static so you can access it
// like MyOtherType.Method1
strategyMap = new Dictionary<MyState, Func<bool>>();
strategyMap.Add(MyState.DoSomething1, myOtherTypeInstance.Method1);
2) Call appropriate strategy depends on state instead of switch(State)
if (starategyMap.ContainsKey(State))
{
// pass in an associated strategy
Process(starategyMap[State]);
}
Feel free to ask in case of any questions
One possible solution is to make the methods static and take the class reference they shall operate on as a parameter:
public class MyOtherType
{
public static bool Method1(MyOtherType instance)
{
return instance == null;
}
}
Given a EF-Code First CTP5 entity layout like:
public class Person { ... }
which has a collection of:
public class Address { ... }
which has a single association of:
public class Mailbox { ... }
I want to do:
PersonQuery.Include(x => x.Addresses).Include("Addresses.Mailbox")
WITHOUT using a magic string. I want to do it using a lambda expression.
I am aware what I typed above will compile and will bring back all Persons matching the search criteria with their addresses and each addresses' mailbox eager loaded, but it's in a string which irritates me.
How do I do it without a string?
Thanks Stack!
For that you can use the Select method:
PersonQuery.Include(x => x.Addresses.Select(a => a.Mailbox));
You can find other examples in here and here.
For any one thats still looking for a solution to this, the Lambda includes is part of EF 4+ and it is in the System.Data.Entity namespace; examples here
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
It is described in this post: http://www.thomaslevesque.com/2010/10/03/entity-framework-using-include-with-lambda-expressions/
Edit (By Asker for readability):
The part you are looking for is below:
public static class ObjectQueryExtensions
{
public static ObjectQuery<T> Include<T>(this ObjectQuery<T> query, Expression<Func<T, object>> selector)
{
string path = new PropertyPathVisitor().GetPropertyPath(selector);
return query.Include(path);
}
class PropertyPathVisitor : ExpressionVisitor
{
private Stack<string> _stack;
public string GetPropertyPath(Expression expression)
{
_stack = new Stack<string>();
Visit(expression);
return _stack
.Aggregate(
new StringBuilder(),
(sb, name) =>
(sb.Length > 0 ? sb.Append(".") : sb).Append(name))
.ToString();
}
protected override Expression VisitMember(MemberExpression expression)
{
if (_stack != null)
_stack.Push(expression.Member.Name);
return base.VisitMember(expression);
}
protected override Expression VisitMethodCall(MethodCallExpression expression)
{
if (IsLinqOperator(expression.Method))
{
for (int i = 1; i < expression.Arguments.Count; i++)
{
Visit(expression.Arguments[i]);
}
Visit(expression.Arguments[0]);
return expression;
}
return base.VisitMethodCall(expression);
}
private static bool IsLinqOperator(MethodInfo method)
{
if (method.DeclaringType != typeof(Queryable) && method.DeclaringType != typeof(Enumerable))
return false;
return Attribute.GetCustomAttribute(method, typeof(ExtensionAttribute)) != null;
}
}
}
Is there any way to check declaratively whether an enum has a specified value. For example:
<h:graphicImage name="error.png" library="images"
rendered="#{viewController.current.status == Status.ERROR}" />
It's a little bit tedious to define a method in the managed beand that checks this for every enum value, e.g.
public boolean isStateIsError() {
return current.getStatus() == Status.ERROR;
}
Is there a shorter/better way of doing this?
Until EL 3.0 it's not possible to import enums in EL scope. You can however just treat and compare them like strings, i.e. the enum constant value must be quoted like below.
<h:graphicImage name="error.png" library="images"
rendered="#{viewController.current.status eq 'ERROR'}" />
I know this question is a bit older now, but i had the same problem and found another solution, which i want to share :
Create a Custom EL-Resolver and use enums and java constants as objects in jsf el:
<h:graphicImage name="error.png" library="images"
rendered="#{viewController.current.status == Status.ERROR}" />
But before you can use enums this way you have to do 3 steps.
1. step - Copy this Class and replace "MY_ENUM" through your enumClass (in the example above it would be "Status")
public class EnumCache {
private Map<String, Object> propertCache = new HashMap<String, Object>();
private Map<String, Class> baseCache = new HashMap<String, Class>();
private static EnumCache staticEnumCache = null;
public static EnumCache instance() {
if (staticEnumCache == null) { staticEnumCache = new EnumCache(); }
return staticEnumCache;
}
private EnumCache() {
List<Class<?>> classes = new ArrayList<Class<?>>();
classes.add(MY_ENUM.class);
for(Class clazz : classes) {
try {
baseCache.put(clazz.getSimpleName(), clazz);
Method m = clazz.getMethod("values", (Class[]) null);
Enum<?>[] valueList = (Enum[]) m.invoke(null, (Object[]) null);
for (Enum<?> en : valueList) {
propertCache.put(clazz.getSimpleName() + "." + en.name(), en);
}
} catch (Exception e) {
System.err.println(clazz.getSimpleName(), e);
}
}
}
public Object getValueForKey(String key) {
return propertCache.get(key);
}
public Class getClassForKey(String key) {
return baseCache.get(key);
}
}
2. step - add this EnumResolver - This class will map your JSF expression to the enum in cache (step 1)
public class MyEnumResolver extends ELResolver {
public Object getValue(ELContext context, Object base, Object property) {
Object result = null;
if (base == null) {
result = EnumCache.instance().getClassForKey(property + "");
} else if (base instanceof Class) {
result = EnumCache.instance().getValueForKey(((Class) base).getSimpleName() + "." + property);
}
if (result != null) {
context.setPropertyResolved(true);
}
return result;
}
public Class<?> getCommonPropertyType(ELContext context, Object base) {
return null;
}
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
return null;
}
public Class<?> getType(ELContext context, Object base, Object property) {
return null;
}
public boolean isReadOnly(ELContext context, Object base, Object property) {
return false;
}
public void setValue(ELContext context, Object base, Object property, Object arg3) {
}
}
3. step - register the EnumResolver in faces-config.xml
<faces-config>
<application>
<el-resolver>com.asd.MyEnumResolver</el-resolver>
</application>
</faces-config>
NOTE:
If you want to access your java constants this way, you just have to extend the constructor of the enumCache class.
This (untestet) example should work:
baseCache.put(CLASS_WITH_CONSTANTS.getSimpleName(), clazz);
for (Field field : CLASS_WITH_CONSTANTS.getDeclaredFields()) {
try {
propertCache.put(CLASS_WITH_CONSTANTS.getSimpleName() + "."
+ field.getName(), field.get(null));
} catch (Exception e) { }
}
Hope this reduced but working code can help anybody.
Update
I see this benefits:
If you use strings in jsf (viewController.current.status == 'ERROR_abcdefg'), you can misspell the value and wont recognise it so fast.
With my solution you would get an error while loading the jsf file, because the enum could not be resolved.
You can see in the sourcecode that "ERROR" is value of the enum "STATUS".
When you compare two values in el, the class of the enums will be compared too.
So for example PersonState.ACTIV is not the same like AccounState.ACTIV.
When i have to change my enum value from PersonState.ACTIV to PersonState.ACTIVATED i can search for the String "PersonState.ACTIV" in my sourcecode. searching for "ACTIV" would have much more matches.
I solved a similar problem by statically dumping all the enum keys (which are used in the rendered UI components) in a map and then I use a static getByKey method to convert the value from the UI into an actual native enum in the setter, throwing an Exception if the value provided is invalid:
public enum ReportType {
FILING("F", "Filings"),
RESOLUTION("R", "Resolutions"),
BASIS("B", "Bases"),
STAFF("T", "Staff Counts"),
COUNTS("I", "Counts");
private String key;
private String label;
private static Map<String, ReportType> keyMap = new HashMap<String, ReportType>();
static {
for(ReportType type : ReportType.values()) {
keyMap.put(type.getKey(), type);
}
}
private ReportType(String _key, String _label) {
this.key = _key;
this.label = _label;
}
public String getKey() {
return this.key;
}
public String getLabel() {
return this.label;
}
public static List<ReportType> getValueList() {
return Arrays.asList(ReportType.values());
}
public static ReportType getByKey(String _key) {
ReportType result = keyMap.get(_key);
if(result == null) {
throw new IllegalArgumentException("Invalid report type key: " + _key);
}
return result;
}
}
In the UI tier, the enum key is used as the value and the enum label is used as the label:
<f:selectItems var="rptTypeItem" value="#{reportController.allReportTypes}"
itemLabel="#{rptTypeItem.label}" itemValue="#{rptTypeItem.key}"/>
In the managed bean, I convert the enum into a renderable list, using the getValueList() from the enum:
public List<ReportType> getAllReportTypes() {
return ReportType.getValueList();
}
Finally, the [g|s]etters in the managed bean look as follows:
public String getReportType() {
return this.crtRptType.getKey();
}
public void setReportType(String _val) {
this.crtRptType = ReportType.getByKey(_val);
}
I think it could be done it the following way:
Create a method in you bean that would return the list of enums, for example
public Status[] getStatuses() {
Status.values();
}
then you can use the enum in EL like this
<h:graphicImage name="error.png" library="images"
rendered="#{viewController.current.status == someBean.statuses[0]}" />
assuming that the order of enum members is not going to be changed (for ex. here statuses[0] is ERROR). However, I would fix the positions like this:
public Status[] getStatuses() {
Status myStatuses = new Status [2]; // or whatever number of statuses you are going to use in UI
myStatuses [0] = Status.ERROR;
myStatuses [1] = Status.RUNNING;
return myStatuses;
}
This is still not dynamic solution, but it's better than hard-coding in EL. Might be especially useful when you'r using localization for you statuses (enum values depending on locale/translation).