How to pass method as a parameter for another method - c#

I need to examine in "parent" object is there an acceptable at a definite moment to call some method in the "child". For example, parent object (component) includes child objects (or component parts in other words) and parent is disposing now, so all (or particlar) child activities must be prohibited (i.e. starting new service threads, enqueueing new client requests, ...).
public class Parent
{
public bool IsMethodCallAcceptable(reference_to_method) {...}
}
public class Child
{
public int SomeMethod(int intArg, string stringArg)
{
if(!_parent.IsMethodCallAcceptable(reference_to_SomeMethod_with_actual_args))
throw new ...
...
}
private void AnotherMethod(string param = null) {...}
{
if(!_parent.IsMethodCallAcceptable(reference_to_AnotherMethod_with_actual_args))
throw new ...
...
}
private Guid ThirdMethod()
{
if(!_parent.IsMethodCallAcceptable(reference_to_ThirdMethod))
throw new ...
...
}
}
Is there any way to do it?

Note: I am answering your question, not your title. Others have answered the title.
Some objects have an isDisposed property, if your parent implements that and that is the only time you don't want to call methods, then yes. Otherwise no. If you control the source for the parent, you could add a property that does what you want.
If you don't control the source and you want to check more than isDisposed or the parent doesn't implement isDisposed, you might be able to check publicly exposed properties, but generally you should assume that if a method is exposed to the public, that it is acceptable to call it at any time. If you're calling private methods via reflection, then you're taking chances.
Edit in response to comment:
Given your description, delegates won't give you any additional capability that you can't do easier by adding properties and methods to the parent (if you don't control the source, they won't help at all). The best method for dealing with your described scenario (CAR.ENGINE.START when out of gas, is for the Start method to either throw an exception or return a value indicationg the result of the attempt to start the engine).

Use delegates?
http://msdn.microsoft.com/en-us/library/ms173171%28v=vs.80%29.aspx

The easiest way is to pass an URI instead of a reference:
"NS.Child.ThirdMethod" for example.
Otherwise, a delegate is what is the closest to a function reference. You can pass that if you want.
However, this method is not compliant with OOP conception rules: Base class should know nothing about its children classes.
It's better to use some kind of locking mechanism to tell the children that they can't have access to the resources.

use func Func<T, TResult>
link

If these methods are native to the child class, the parent can't know anything about them for sure. Rice's Theorem will cause you all kinds of problems, if you could even see the code. Same problem (but to a lesser degree) if they're native to the parent class and are being overridden in the child, since you can't really guarantee that the child class will be doing everything (and only those things) that the parent class does; in fact, you can all but guarantee it will do something different. (If it didn't, why override?)
If they're native to the parent class and not overridable in the child, then just check whether the object is in a valid state for doing such a thing and throw an exception if it isn't.
As far as the actual validity check, for your example you can have a method like bool IsDisposing(); for other cases, you might keep track of the state in some other way. A private method like CanDoThisThing() might help, for example. Having a method that takes a generic operation name (not an operation; we already established the infeasibility of that) seems kinda broken to me.

Thank you all again, the result in the first approach is listed below
public class Component
{
public ComponentPart SomeComponentPart1 { get; private set; }
public ComponentPart SomeComponentPart2 { get; private set; }
public Component()
{
SomeComponentPart1 = new ComponentPart(this);
SomeComponentPart2 = new ComponentPart(this);
}
public bool IsMethodCallAcceptable(MethodCallExpression method, object[] parameters)
{
// collect needed information about caller
var caller = (method.Object as ConstantExpression).Value;
var methodName = method.Method.Name;
var paramsArray = new Dictionary<string, object>();
for (int i = 0; i < method.Arguments.Count; i++)
paramsArray.Add((method.Arguments[i] as MemberExpression).Member.Name, parameters[i]);
// make corresponding decisions
if (caller == SomeComponentPart2)
if (methodName == "SomeMethod")
if ((int) paramsArray["intArg"] == 0 || (string) paramsArray["stringArg"] == "")
return false;
return true;
}
}
public class ComponentPart
{
private Component Owner { get; set; }
public ComponentPart(Component owner)
{
Owner = owner;
}
public int SomeMethod(int intArg, string stringArg)
{
// check if the method call with provided parameters is acceptable
Expression<Func<int, string, int>> expr = (i, s) => SomeMethod(intArg, stringArg);
if (!Owner.IsMethodCallAcceptable(expr.Body as MethodCallExpression, new object[] { intArg, stringArg }))
throw new Exception();
// do some work
return stringArg.Length + intArg;
}
public void AnotherMethod(bool boolArg, Dictionary<Guid, DateTime> crazyArg, string stringArg, object objectArg)
{
// check if the method call with provided parameters is acceptable
Expression<Action<bool, Dictionary<Guid, DateTime>, string, object>> expr =
(b, times, arg3, arg4) => AnotherMethod(boolArg, crazyArg, stringArg, objectArg);
if (!Owner.IsMethodCallAcceptable(expr.Body as MethodCallExpression, new [] { boolArg, crazyArg, stringArg, objectArg }))
throw new Exception();
// do some work
var g = new Guid();
var d = DateTime.UtcNow;
}
}
This is variant how to check method calls, the same approach can be used in order to check properties values changes, while some ComponentPart' methods and properties can check some public Component.State property (via ComponentPart.Owner) instead of calling Component.IsMethodCallAcceptable or Component.IsPropertyChangeAcceptable.

Related

Getting all results from Func call

The concept of delegates aren't too new to me but I cannot seem to find out how to get all results from a Func delegates. More specifically, I have a class that has a Func delegate that returns a type bool. Something like this...
private Func<Employee, Shift, bool> qualificationCheckCallback;
There are both 'register' and 'unregister' methods for the callback as well. My goal is to see if any of the methods stored in the delegate return false when invoked later in code. Any insight you may have on this issue is much appreciated! Thanks.
You are using the wrong pattern. I'd recommend storing a list of these delegates and iterating over the list, rather than using multidelegates to call multiple targets.
You can make this work (if you need to) by changing the signature to include a "state" variable that is passed by reference to each caller:
private Action<Employee, Shift, QualCheckState> qualificationCheckCallback;
public class QualCheckState { public bool Passed { get; set; } }
// Call it thus:
var state = new QualCheckState { Passed = true }; // Hope for the best
qualificationCheckCallback(someEmployee, someShift, state);
if (state.Passed) {
// Assume everyone passed
}
Keep in mind, this requires the callees to honor the signature, and not overwrite anyone else's failed state:
public void SomeCallee(Employee e, Shift s, State state) {
// If some other check failed, don't bother doing our check.
if (!state.Passed) return;
// Do some check here
if (checkFailed) state.Passed = false;
}
Of course, you can also extend this pattern to make it safer:
public class QualCheckState {
private List<bool> _results = new List<bool>();
public bool Passed { get { return _results.All(s => s); }
public void RecordResult(bool result) {
_results.Add(result);
}
}
As mentioned in Andrew's answer, if you simply invoke qualificationCheckCallback like a normal method, you'll only get back the return value from one of the methods. For this reason, it's pretty unusual to have multicast delegates that have a return value.
If your goal is to see if at least one of the methods stored in your delegate returns false, you'll need to invoke the methods individually. Here is one way to do that using the Delegate.GetInvocationList() method:
bool hasAtLeastOneFalse = false;
if (qualificationCheckCallback != null)
{
foreach(var f in qualificationCheckCallback.GetInvocationList()
.Cast<Func<Employee, Shift, bool>>())
{
if (!f(employee, shift))
{
hasAtLeastOneFalse = true;
// break; // If you don't care about invoking all delegates, you can choose to break here.
}
}
}
Console.WriteLine(hasAtLeastOneFalse);
I'm not suggesting this is a good practice, but it can be done.
A quick search on MSDN found this thread:
https://social.msdn.microsoft.com/Forums/en-US/38a638fe-4a7d-44d6-876c-729d90c20737/how-to-get-return-value-from-delegate?forum=csharplanguage
The problem with events is that the return values cannot be fully
trusted. You will get only one return value no matter how many
subscribers that you have for the event. The central issue is that
you cannot reliably determine which subscriber produced the return
value. The beauty of the .NET Event Model is the anonymity that it
uses. That means event subscribers are completely abstracted from the
event publishers.

How to get Type name of a CallerMember

I got this class
public class fooBase
{
public List<MethodsWithCustAttribute> MethodsList;
public bool fooMethod([CallerMemberName]string membername =""))
{
//This returns a value depending of type and method
}
public void GetMethods()
{
// Here populate MethodsList using reflection
}
}
And This Attribue Class
// This attribute get from a database some things, then fooMethod check this attribute members
public class CustomAttribute
{
public string fullMethodPath;
public bool someThing ;
public bool CustomAttribute([CallerMemberName]string membername ="")
{
fullMethodPath = **DerivedType** + membername
// I need here to get the type of membername parent.
// Here I want to get CustClass, not fooBase
}
}
Then I have this
public class CustClass : fooBase
{
[CustomAttribute()]
public string method1()
{
if (fooMethod())
{
....
}
}
}
I need the Type name of the CallerMember, there is something like [CallerMemberName] to get the Type of class owner of the Caller ?
It isn't foolproof, but the convention with .NET is to have one type per file and to name the file the same as the type. Our tooling also tends to enforces this convention i.e. Resharper & Visual Studio.
Therefore it should be reasonable to infer the type name from the file path.
public class MyClass
{
public void MyMethod([CallerFilePath]string callerFilePath = null, [CallerMemberName]string callerMemberName = null)
{
var callerTypeName = Path.GetFileNameWithoutExtension(callerFilePath);
Console.WriteLine(callerTypeName);
Console.WriteLine(callerMemberName);
}
}
Caller member
Granted, getting the caller member name is not "natural" in the object model.
That's why the C# engineers introduced CallerMemberName in the compiler.
The real enemy is duplication, and stack-based workarounds are inefficient.
[CallerMemberName] allows to get the information without duplication and without ill-effect.
Caller type
But getting the caller member type is natural and easy to get without duplication.
How to do it
Add a "caller" parameter to fooMethod, no special attribute needed.
public bool fooMethod(object caller, [CallerMemberName]string membername = "")
{
Type callerType = caller.GetType();
//This returns a value depending of type and method
return true;
}
And call it like this:
fooMethod(this);
This answer the question
You stated
// Here I want to get CustClass, not fooBase
and that's exactly what you'll get.
Other situations where it would not work, with solutions.
While this exactly answers your requirements, there are other, different, cases where it wouldn't work.
Case 1: When caller is a static methods (there is no "this").
Case 2: When one wants the type of the caller method itself, and not the type of the caller itself (which may be a subclass of the first).
In those cases, a [CallerMemberType] might make sense, but there are simpler solutions.
Notice that the static caller case is simpler: there is no object so no discrepancy between it and the type of the calling method. No fooBase, only CustClass.
Case 1: When caller is a static methods (there is no "this")
If at least one caller is a static method, then don't do the GetType() inside the method but on call site, so don't pass "this" to the method but the type:
public bool fooMethodForStaticCaller(Type callerType, [CallerMemberName]string membername = "")
Static caller will do:
public class MyClassWithAStaticMethod // can be CustClass, too
{
public static string method1static()
{
fooMethodForStaticCaller(typeof(MyClassWithAStaticMethod));
}
}
To keep compatibility with object callers, either keep the other fooMethod that takes the this pointer, or you can remove it and object callers will do:
fooMethod(this.GetType());
You can notice that the typeof(MyClassWithAStaticMethod) above repeats the class name and it's true. It would be nicer to not repeat the class name, but it's not such a big deal because this repeats only once, as a typed item (not a string) and inside the same class. It's not as serious a problem as the original problem that the [CallerMemberName] solves, which was a problem of repeating the caller name in all call sites.
Case 2: When one wants the type of the caller method, not the type of the caller
For example, in class fooBase you want to call anotherFooMethod from object context but want the type being passed to always be fooBase, not the actual type of the object (e.g. CustClass).
In this case there is a this pointer but you don't want to use it. So, just use actually the same solution:
public class fooBase
{
[CustomAttribute()]
public string method1()
{
if (anotherFooMethod(typeof(fooBase)))
{
....
}
}
}
Just like in case 1, there is one repetition, not one per call site, unless you have an pre-existing problem of rampant code duplication, in which case the problem being addressed here is not the one you should worry about.
Conclusion
[CallerMemberType] might still make sense to avoid duplication at all, but:
anything added to the compiler is a complexity burden with maintenance cost
given the existing solutions I'm not surprised there are items with higher priority in the C# development team list.
See Edit 2 for the better solution.
The information that CompilerServices provides is too little in my opinion to get the type from the calling method.
What you could do is use StackTrace (see) to find the calling method (using GetMethod()) and get the type using Reflection from there.
Consider the following:
using System.Runtime.CompilerServices;
public class Foo {
public void Main() {
what();
}
public void what() {
Bar.GetCallersType();
}
public static class Bar {
[MethodImpl(MethodImplOptions.NoInlining)] //This will prevent inlining by the complier.
public static void GetCallersType() {
StackTrace stackTrace = new StackTrace(1, false); //Captures 1 frame, false for not collecting information about the file
var type = stackTrace.GetFrame(1).GetMethod().DeclaringType;
//this will provide you typeof(Foo);
}
}
}
Notice - As #Jay said in the comments, it might be pretty expensive but it does the work well.
Edit:
I found couple of arcticles comparing the performance, and it is indeed horrbily expensive comparing to Reflection which is also considered not the best. See: [1] [2]
Edit 2:
So after a look in depth on StackTrace, it is indeed not safe to use it and even expensive.
Since every method that will be called is going to be marked with a [CustomAttribute()], it is possible to collect all methods that contains it in a static list.
public class CustomAttribute : Attribute {
public static List<MethodInfo> MethodsList = new List<MethodInfo>();
static CustomAttribute() {
var methods = Assembly.GetExecutingAssembly() //Use .GetCallingAssembly() if this method is in a library, or even both
.GetTypes()
.SelectMany(t => t.GetMethods())
.Where(m => m.GetCustomAttributes(typeof(CustomAttribute), false).Length > 0)
.ToList();
MethodsList = methods;
}
public string fullMethodPath;
public bool someThing;
public CustomAttribute([CallerMemberName] string membername = "") {
var method = MethodsList.FirstOrDefault(m=>m.Name == membername);
if (method == null || method.DeclaringType == null) return; //Not suppose to happen, but safety comes first
fullMethodPath = method.DeclaringType.Name + membername; //Work it around any way you want it
// I need here to get the type of membername parent.
// Here I want to get CustClass, not fooBase
}
}
Play around with this approach to fit your precise need.
Why not just use public void MyMethod<T>(params) { string myName = typeof(T).Name }
then call it Logger.MyMethod<Form1>(...);
You avoid the performance hit of reflection, if you just need basic info.

Ninject Memoize Instances in Singleton Scope

I'm using Ninject to instantiate some objects with a constructor arg passed, e.g.:
class MyClass
{
public MyClass(string myArg)
{
this.myArg = myArg;
}
}
The number of instances I need of this class won't be known until runtime, but what I want to do is ensure that each variation of myArg results in a different singleton instance (so asking for the same value twice returns the same instance, but different args return different instances).
Does anyone know of a good, preferably built-in, way of doing this?
I found an article written for an older version of Ninject How To Ensure One Instance per Variation of Activation Parameters but was hoping there'd be a tidier solution for the newer version.
Edit
Here's what I went with, adapted from Akim's answer below:
private readonly ConcurrentBag<string> scopeParameters = new ConcurrentBag<string>();
internal object ParameterScope(IContext context, string parameterName)
{
var param = context.Parameters.First(p => p.Name.Equals(parameterName));
var paramValue = param.GetValue(context, context.Request.Target) as string;
paramValue = string.Intern(paramValue);
if (paramValue != null && !scopeParameters.Contains(paramValue))
{
scopeParameters.Add(paramValue);
}
return paramValue;
}
public override void Load()
{
Bind<MyClass>()
.ToSelf()
.InScope(c => ParameterScope(c, "myArg"));
Bind<IMyClassFactory>()
.ToFactory();
}
You could achieve require behaviour by providing custom scope using IBindingNamedWithOrOnSyntax<T> InScope(Func<IContext, object> scope) method for MyClass binding
Indicates that instances activated via the binding should be re-used
as long as the object returned by the provided callback remains alive
(that is, has not been garbage collected).
So, you need to return value of first constructor argument from Func<IContext, object> scopeand make sure that garbage-collector would not collect it.
Here is a snippet:
public class Module : NinjectModule
{
// stores string myArg to protect from CG
ConcurrentBag<string> ParamSet = new ConcurrentBag<string>();
public override void Load()
{
Bind<MyClass>()
.ToSelf()
// custom scope
.InScope((context) =>
{
// get first constructor argument
var param = context.Parameters.First().GetValue(context, context.Request.Target) as string;
// retrieves system reference to string
param = string.Intern(param);
// protect value from CG
if(param != null && ParamSet.Contains(param))
{
// protect from GC
ParamSet.Add(param);
}
// make Ninject to return same instance for this argument
return param;
});
}
}
ps: full sample code with unittests

How to identify an anonymous function

I have a class that creates a List<Action<int>> and holds on to them until a later time. This class can add and remove delegates from this list. This works well as long as people don't get too fancy. To combat anonymous function (which can't be removed) I check against the target of the delegate being null. If its null I throw an exception. The problem comes in when there is an anonymous delegate that contains a function. This has a target, but is just as unremovable. The simplified code below illustrates my issues
public class MyDelegateContainer
{
List<Action<int>> m_Container = new List<Action<int>>();
public void Add(Action<int> del)
{
if (del.Target == null)
{
throw new Exception("No static handlers");
}
m_Container.Add(del);
}
public bool Remove(Action<int> del)
{
if (m_Container.Contains(del))
{
m_Container.Remove(del);
return true;
}
return false;
}
}
public class MyFakeActionClass
{
public void Test(int temp) { }
}
class Program
{
static void Main(string[] args)
{
bool removed = false;
int counter = 0;
MyDelegateContainer container = new MyDelegateContainer();
MyFakeActionClass fake = new MyFakeActionClass();
//container.Add(p => { }); //Throws, this is what I want to happen
container.Add(fake.Test); //Works, this is the use case
removed = container.Remove(fake.Test); //Works, this is the use case
Debug.Assert(removed);
container.Add(p => { fake.Test(p); counter++; }); //Works but I would like it not to
removed = container.Remove(p => { fake.Test(p); counter++; }); //doesn't work
Debug.Assert(removed);
}
}
I need some way to identify
p => { fake.Test(p); counter++; }
is an anonymous function so I can throw if someone tries it. Thanks for any help
EDIT: I should note that I could use an Action<int> variable for the anonymous function and everything would work, but the Add and Remove are never in the same scope in practice.
In your example, the caller is responsible from removing the handler. So, if the caller doesn't want to remove the handler, it won't get removed, no matter if the handler is an anonymous delegate/lambda or not.
My suggestion is to change the delegate container to something like this:
public class MyDelegateContainer
{
List<Action<int>> m_Container = new List<Action<int>>();
public Action Add(Action<int> del)
{
m_Container.Add(del);
return new Action(() =>
{
m_Container.Remove(del);
});
}
}
The caller is still responsible for removing the handler, but instead of passing the handler again to the container, it receives a "token" that it can save and use later to remove the handler.
There is no way to reliably determine whether a function is "anonymous" because all functions have names to the CLR. It's only anonymous within the language that generates it, and that's compiler-dependent. You may be able to determine the algorithm used by Microsoft's current C# compiler, only to have it stop working on C# 5 or Mono.
Since you want to prevent users of your type from writing code that uses it wrong, you just need to throw an exception at some point that will make their program crash. What I would do is throw the exception in the Remove function when the target delegate isn't found. At that point your users will still get a crash and the only way to fix it is to write the delegate in some way that it's removable.
As an added bonus, you will catch bugs where somebody tries to remove delegates twice or that were never added in the first place. The code would look like this:
public bool Remove(Action<int> del)
{
if (m_Container.Contains(del))
{
m_Container.Remove(del);
return true;
}
throw new ArgumentException("Attempt to remove nonexistent delegate");
}
I would use introspection to check the names of the methods.
Anonymous methods typically have very predictable names. (I don't remember the exact format, but run some tests, and it should be obvious).
The drawback would be that if anyone created a non-anonymous method, but decided to name it anonMethod123 (or whatever the format is...) It would be falsely rejected.
Of course you can remove an anonymous method, you just need to have a reference to the same anonymous method.
var myAnonymousMethod = p => { fake.Test(p); counter++; };
container.Add(myAnonymousMethod);
removed = container.Remove(myAnonymousMethod);
As jonnii suggested in a comment, another way you could implement it is with a dictionary:
public class MyDelegateContainer
{
Dictionary<string, Action<int>> m_Container =
new Dictionary<string, Action<int>>();
public void Add(string key, Action<int> del)
{
m_Container.Add(key, del);
}
public bool Remove(string key)
{
return m_Container.Remove(key);
}
}
Then you could easily remove a known delegate at some arbitrary point in your code just by knowing what name was used to add it:
container.Add("fake.Test", fake.Test);
removed = container.Remove("fake.Test");
Debug.Assert(removed);
container.Add("anon", p => { fake.Test(p); counter++; });
removed = container.Remove("anon"); // works!
Debug.Assert(removed);
Old question I know but I would think that this would be a current (and future) proofed way of checking if a method is anonymous:
bool isAnonymous = !System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(del.Method.Name);
The runtime name of the anonymous method would have to be invalid if used at compilation time to ensure that it didn't clash.

Strongly-typed property reference to multiple classes with no common interface (C#)

The System.Windows.Documents namespace includes a number of classes with an Inlines property of type InlineCollection. For example, the Paragraph, Bold and Hyperlink classes all have this property.
Each of these classes is decorated with ContentPropertyAttribute ...
[ContentPropertyAttribute("Inlines")]
public class Paragraph : Block
... which means that it is easy enough, using reflection, to detect that a given object exposes this property.
However, I need to be able to access this property in a strongly-typed manner across a selection of the types that implement it.
I am a little surprised that Microsoft didn't make all these classes implement an "IInlineContainer" interface, which would have made type checking and casting very easy.
However, in the absence of such an interface, is there any way to fake this polymorphic functionality, ideally without littering my code with lots of conditions and type checking?
Many thanks for your ideas,
Tim
Edit:
Thanks for your suggestions. A number of people have suggested the idea of a wrapper class, but this is not possible in my situation, as the target objects are not created by my code, but by the other classes in the .NET framework, for example the Xaml parser or the RichTextBox control (in which the containing FlowDocument is being edited).
Edit 2:
There have been several great suggestions here and I thank everyone who shared their ideas. The solution I have chosen to implement employs extension methods, which was suggested by #qstarin, although I have refined the concept to suit my needs, as follows:
public static InlineCollection GetInlines(
this FrameworkContentElement element)
{
if (element == null) throw new ArgumentNullException("element");
if (element is Paragraph)
{
return ((Paragraph) element).Inlines;
}
else if (element is Span) // also catches Bold, Italic, Unerline, Hyperlink
{
return ((Span)element).Inlines;
}
else
{
return null;
}
}
Although this approach requires conditional logic and type casting (which I said I wanted to avoid) the use of extension methods means that it only needs to be implemented in one place, leaving my various calling methods uncluttered.
Extension methods.
public static class InlineContainerExtensions {
public static InlineContainer GetInlines(this Paragraph inlineContainer) {
return inlineContainer.Inlines;
}
public static InlineContainer GetInlines(this Bold inlineContainer) {
return inlineContainer.Inlines;
}
}
If you didn't need to access it in a strongly-typed manner, but just without reflection, you could use dynamic:
dynamic doc = new Bold()
doc.InlineCollection. ...
doc = new Paragraph()
doc.InlineCollection. ...
Another option is to define a wrapper, that exposes a property with the same name, and has an overloaded constructor that takes Bold, Paragraph, etc.
You could implement a wrapper class that exposes an Inlines property and delegates via reflection to the contained object.
Decide if you want to validate that the wrapped object indeed has Inlines in your constructor or when trying to reference it
Employ the Adapter Pattern, write one class for each of those classes you wish to handle, effectively wrapping them in a layer implementing a common layer.
To make the classes discoverable, I would use reflection, tag each such class with an attribute for which class they handle, ie.:
[InlineContainerAdapter(typeof(SpecificClass1))]
public class WrapSpecificClass1 : IInlineContainer
and use reflection to find them.
This would give you several benefits:
You don't have to deal with dynamic, or similar solutions
While you have to use reflection to find the classes, the code you're actually executing once you've created the adapter is 100% yours, hand-coded
You can create adapters for classes that doesn't really implement what you need in the same manner as the rest, by just writing the adapter different
If this sounds like an interesting solution, leave a comment and I'll put up a working complete example.
One way of doing this (apart from using dynamic, which is the easiest solution IMO), you can create dynamically generated methods to return the inlines:
Func<object, InlineCollection> GetInlinesFunction(Type type)
{
string propertyName = ...;
// ^ check whether type has a ContentPropertyAttribute and
// retrieve its Name here, or null if there isn't one.
if (propertyName == null)
return null;
var p = Expression.Parameter(typeof(object), "it");
// The following creates a delegate that takes an object
// as input and returns an InlineCollection (as long as
// the object was at least of runtime-type "type".
return Expression.Lambda<Func<object, InlineCollection>>(
Expression.Property(
Expression.Convert(p, type),
propertyName),
p).Compile();
}
You'd have to cache these somewhere, though. A static Dictionary<Type, Func<object, InlineCollection>> comes to mind. Anyway, when you have, you can simply make an extension method:
public static InlineCollection GetInlines(this TextElement element)
{
Func<object, InlineCollection> f = GetCachedInlinesFunction(element.GetType());
if (f != null)
return f(element);
else
return null;
}
Now, with this in place, just use
InlineCollection coll = someElement.GetInlines();
Because you can check in your GetCachedInlinesFunction whether the property really exists or not, and handle that in a neat fashion, you won't have to litter your code with try catch blocks like you have to when you're using dynamic.
So, your dream-code would be:
foreach (var control in controls) {
var ic = control as IInlineContainer;
if (ic != null) {
DoSomething(ic.Inlines);
}
}
I don't see why you don't want to create a strongly typed wrapper class that uses reflection. With this class (no error handling):
public class InlinesResolver {
private object _target;
public InlinesResolver(object target) {
_target = target;
}
public bool HasInlines {
get {
return ResolveAttribute() != null;
}
}
public InlineCollection Inlines {
get {
var propertyName = ResolveAttribute().Name;
return (InlineCollection)
_target.GetType().GetProperty(propertyName).GetGetMethod().Invoke(_target, new object[] { });
}
}
private ContentPropertyAttribute ResolveAttribute() {
var attrs = _target.GetType().GetCustomAttributes(typeof(ContentPropertyAttribute), true);
if (attrs.Length == 0) return null;
return (ContentPropertyAttribute)attrs[0];
}
}
You could almost get to your dream-code:
foreach (var control in controls) {
var ir = new InlinesResolver(control);
if (ir.HasInlines) {
DoSomething(ir.Inlines);
}
}
You could always superclass them (e.g. InlineParagraph, InlineBold, etc) and have each of your superclasses implement an IInlineContainer interface like you suggested. Not the quickest or cleanest solution, but you at least have them all descending from the same interface.
Depending on your use-case, you could create a public Api that delegated its work to a private method that takes a dynamic. This keeps the strong typing for your public Api and eliminates code duplication, even though it falls back to using dynamic internally.
public void DoSomethingwithInlines(Paragraph p) {
do(p);
}
public void DoSomethingwithInlines(Bolb b) {
do(b);
}
private void do(dynamic d) {
// access Inlines here, using c# dynamic
}

Categories

Resources