I have the following Class which inherits IEnumerable
public class LinesEnumerable : IEnumerable<Point>
{
protected readonly IPointSeries _pointSeries;
protected readonly ICoordinateCalculator<double> _xCoordinateCalculator;
protected readonly ICoordinateCalculator<double> _yCoordinateCalculator;
protected readonly bool _isDigitalLine;
/// <summary>
/// Initializes a new instance of the <see cref="LinesEnumerable" /> class.
/// </summary>
/// <param name="pointSeries">The point series.</param>
/// <param name="xCoordinateCalculator">The x coordinate calculator.</param>
/// <param name="yCoordinateCalculator">The y coordinate calculator.</param>
/// <param name="isDigitalLine">if set to <c>true</c> return a digital line .</param>
public LinesEnumerable(IPointSeries pointSeries, ICoordinateCalculator<double> xCoordinateCalculator, ICoordinateCalculator<double> yCoordinateCalculator, bool isDigitalLine)
{
_pointSeries = pointSeries;
_xCoordinateCalculator = xCoordinateCalculator;
_yCoordinateCalculator = yCoordinateCalculator;
_isDigitalLine = isDigitalLine;
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
public virtual IEnumerator<Point> GetEnumerator()
{
return _isDigitalLine ?
(IEnumerator<Point>)new DigitalLinesIterator(_pointSeries, _xCoordinateCalculator, _yCoordinateCalculator) :
new LinesIterator(_pointSeries, _xCoordinateCalculator, _yCoordinateCalculator);
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
However, when I try to do the following:
linesEnumerable = linesEnumerable.Concat(new[] { new Point(viewportWidth, lastYCoordinate) });
it says 'System.Collections.IEnumerable' does not contain a definition for 'Concat' and the best extension method overload 'System.Linq.Queryable.Concat(System.Linq.IQueryable, System.Collections.Generic.IEnumerable)' has some invalid arguments
I already have System.Linq namespace added
Anybody know why this is happening?
The compiler will give this error when the two collections are of different types T. For example:
List<int> l1 = new List<int>();
List<string> l2 = new List<string>();
var l3 = l1.Concat(l2);
var l4 = l1.Union(l2);
The Concat and Union calls will result in the following compile-time errors respectively:
'List' does not contain a definition for 'Concat' and the best extension method overload 'Queryable.Concat(IQueryable, IEnumerable)' requires a receiver of type 'IQueryable'
'List' does not contain a definition for 'Union' and the best extension method overload 'Queryable.Union(IQueryable, IEnumerable)' requires a receiver of type 'IQueryable'
It is confusing because the message is misleading and VS intellisense recognizes the extension methods. The solution is that l1 and l2 must be lists of the same type T.
Well this won't help you but this question is the top result when you google the error so I'm going to say what my problem was.
I had the following classes:
class Group
class Row : Group
class Column : Group
I was trying to call Concat on an IEnumerable<Row> with an IEnumerable<Column> to get an IEnumerable<Group>. This doesn't work because you can't convert the columns to rows. The solution was to cast my IEnumerable<Row> to IEnumerable<Group>.
e.g. rows.Cast<Group>().Concat(columns)
Related
I have implemented some sort of LINQ Range operator and do want to have a test which will verify that the Range operator is actually deferred.
My Range operator methods:
/// <summary>
/// The Range static method, validation part.
/// </summary>
/// <param name="start">The start.</param>
/// <param name="count">The count.</param>
/// <returns></returns>
public static IEnumerable<int> Range(int start, int count)
{
long max = ((long) start) + count - 1;
if (count < 0 || max > Int32.MaxValue) throw new ArgumentOutOfRangeException(nameof(count));
return RangeIterator(start, count);
}
/// <summary>
/// The Range operator iterator.
/// </summary>
/// <param name="start">The start.</param>
/// <param name="count">The count.</param>
/// <returns></returns>
static IEnumerable<int> RangeIterator(int start, int count)
{
for (int i = 0; i < count; ++i)
{
yield return start + i;
}
}
For the other deferred operators I have created ThrowingExceptionEnumerable utility class, which helps with testing:
/// <summary>
/// The class responsible for verifying that linq operator is deferred.
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class ThrowingExceptionEnumerable<T> : IEnumerable<T>
{
/// <summary>
/// The methods throws <see cref="InvalidOperationException"/>.
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
throw new InvalidOperationException();
}
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// The method which checks that the given <see cref="deferredFunction"/> actually uses deferred execution.
/// When the function just call itself it should not throw an exception. But, when using the result
/// by calling <see cref="GetEnumerator"/> and than GetNext() methods should throws the <see cref="InvalidOperationException"/>.
/// </summary>
/// <typeparam name="TSource">The deferred function source type.</typeparam>
/// <typeparam name="TResult">The deferred function result type.</typeparam>
/// <param name="deferredFunction">The deferred function (unit of work under the test).</param>
public static void AssertDeferred<TSource,TResult>(
Func<IEnumerable<TSource>, IEnumerable<TResult>> deferredFunction)
{
var source = new ThrowingExceptionEnumerable<TSource>();
// Does not throw any exception here, because GetEnumerator() method is not yet used.
var result = deferredFunction(source);
// Does not throw InvalidOperationException even here, despite the fact that we retrieve the enumerator.
using var iterator = result.GetEnumerator();
Assert.Throws<InvalidOperationException>(() => iterator.MoveNext());
}
And for instance deferred Select operator has the following test:
/// <summary>
/// Should check that Select operator is deferred.
/// </summary>
[Fact]
public void VerifySelectExecutionIsDeferred()
{
ThrowingExceptionEnumerable<int>.AssertDeferred<int, int>(source => source.Select(x => x));
}
The first problem I have faced during writing such unit test for the Range operator is that Range is actually a static method and not an extension method. Also the thing is, that Range signature does not have a source parameter, so the same approach can not be used.
Do you have some clever ideas, how it can be tested?
External code isn't going to be able to do anything to verify that the values are generated on the fly. The only actual difference between a method like this and one that materializes a collection and returns it is the memory footprint at scale, which is quite difficult to reliably test in a unit test.
You can clearly tell that it doesn't do that my looking at the code, but you'd need to alter the implementation in some pretty significant way to end up with something that would allow you to verify that in a unit test (such as writing a more generalized "Generate" method that used a delegate to generate the next value).
If you had some sort of hard requirement that your implementation has unit tests to verify such things, I'd write such a Generate method, implement your Range method by calling Generate, write a unit test to verify that Generate doesn't call the delegate until generating the next value in the sequence, and then assert that the Range method defers execution because it uses Generate to produce its sequence. I wouldn't want to do this in production code though, this would really be just a way of meeting the requirement and making some sacrifices in readability and (mild) performance for the sake of it.
I have recently begun using autofac, migrating away from structuremap and lamar. With the previous dependency injection tools it was seemingly rather trivial to resolve all services that closed on the full hierarchy (all interfaces, and base classes) of a given type.
For example structuremap / lamar simply required scanning
// ... registry stuff...
Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.ConnectImplementationsToTypesClosing(typeof(IAnimalFeeder<>));
});
and resolution was just a matter of calling GetAllInstances on the context:
var openFeederType = typeof(IAnimalFeeder<>);
var animalType = typeof(animal);
var closedType = openFeederType.MakeGenericType(animalType);
var feeders = context.GetAllInstances(closedType) // resolve all feeders for given animal hierarchy
However, this does not appear to be the case with autofac. Unless I'm missing some documentation and missuderstanding methods it appears that I need to jump though a number of reflection calls in order to manually determine what the type hierarchy of my service type is, close a generic on each discovered type, close that generic on an IEnumerable and finally make a Resolve call on each closed IEnumerable.
What follows is my approach, and I want to be sure it is valid and not reimplementing existing functionalty
Given our favorite polymorphic animal examples
public interface IAnimal { }
public class Dog : AbstractAnimal { }
public class Wolf : Dog { }
public class Cat : AbstractAnimal { }
I want to discover (Resolve) all feeders, defined below, that can feed an animal
public interface IAnimalFeeder<in TAnimal> { }
public abstract class AbstractAnimal : IAnimal { }
public class AnimalFeeder : IAnimalFeeder<IAnimal> { }
public class ObjectFeeder : IAnimalFeeder<object> { }
public class DogSnackFeeder : IAnimalFeeder<Dog> { }
public class DogFeeder : IAnimalFeeder<Dog> { }
public class WolfFeeder : IAnimalFeeder<Wolf> { }
public class CatFeeder : IAnimalFeeder<Cat> { }
eg:
A DogFeeder can feed both Dog and Wolf, but not Cat
An ObjectFeeder can feed Dog, Wolf, Cat, but not IAnimal
An AnimalFeeder can feed Dog, Wolf, Cat, and IAnimal
etc.
To prove this out I've written an xuint theory with a custom reflection based Resolve in the static ResolutionHelper class (ResolveManyClosedGenericsOfTypeHierarchy) to do my resolution
public class GenericResolveTests
{
[Theory]
[InlineData(new[] {typeof(ObjectFeeder), typeof(AnimalFeeder), typeof(DogFeeder), typeof(DogSnackFeeder)}, typeof(Dog))]
[InlineData(new[] {typeof(ObjectFeeder), typeof(AnimalFeeder), typeof(DogFeeder), typeof(DogSnackFeeder), typeof(WolfFeeder)}, typeof(Wolf))]
[InlineData(new[] {typeof(ObjectFeeder), typeof(AnimalFeeder), typeof(CatFeeder)}, typeof(Cat))]
[InlineData(new[] {typeof(ObjectFeeder)}, typeof(object))]
[InlineData(new[] {typeof(AnimalFeeder)}, typeof(IAnimal))]
public void Generic_Resolve_Test(Type[] expectedTypes,
Type closureType)
{
// Arrange
var assembly = Assembly.GetExecutingAssembly();
var builder = new ContainerBuilder();
// Registration
builder.RegisterAssemblyTypes(assembly) // Register sourcing from the given assembly
.PublicOnly() // Only register public classes
.AsClosedTypesOf(typeof(IAnimalFeeder<>)) // Register types that are assignable to a closed instance of the open generic type IAnimalFeeder<>
.AsSelf() // Register types as themselves (explicit concrete types are made available)
.AsImplementedInterfaces(); // Register the type as providing all of its public interfaces as services
var container = builder.Build();
// Act
// Resolution with non-standard autofac Resolve functionality
var result = container.ResolveManyClosedGenericsOfTypeHierarchy(closureType, typeof(IAnimalFeeder<>));
// Assert
Assert.NotNull(result);
var results = result.ToList();
Assert.Equal(expectedTypes.Length, results.Count);
var resultTypes = results.Select(r => r.GetType())
.ToList();
Assert.All(expectedTypes,
expectedType => Assert.Contains(expectedType, resultTypes));
}
}
public static class ResolutionHelper
{
/// <summary>
/// Resolve closed generics of <paramref name="openGenericType" /> based on the type hierarchy of
/// <typeparamref name="TServiceClosure" />
/// </summary>
/// <typeparam name="TServiceClosure">the service closure type</typeparam>
/// <param name="componentContext">the component context used for resolution</param>
/// <param name="openGenericType">the open generic type to close</param>
/// <returns>
/// a collection of closed <see cref="openGenericType" /> on the type hierarchy of
/// <typeparamref name="TServiceClosure" />
/// </returns>
public static IEnumerable<object> ResolveManyClosedGenericsOfTypeHierarchy<TServiceClosure>(this IComponentContext componentContext,
Type openGenericType)
{
return ResolveManyClosedGenericsOfTypeHierarchy(componentContext.Resolve, typeof(TServiceClosure), openGenericType);
}
/// <summary>
/// Resolve closed generics of <paramref name="openGenericType" /> based on the type hierarchy of
/// <typeparamref name="TServiceClosure" />
/// </summary>
/// <typeparam name="TServiceClosure">the service closure type</typeparam>
/// <param name="container">the container used for resolution</param>
/// <param name="openGenericType">the open generic type to close</param>
/// <returns>
/// a collection of closed <see cref="openGenericType" /> on the type hierarchy of
/// <typeparamref name="TServiceClosure" />
/// </returns>
public static IEnumerable<object> ResolveManyClosedGenericsOfTypeHierarchy<TServiceClosure>(this IContainer container,
Type openGenericType)
{
return ResolveManyClosedGenericsOfTypeHierarchy(container.Resolve, typeof(TServiceClosure), openGenericType);
}
/// <summary>
/// Resolve closed generics of <paramref name="openGenericType" /> based on the type hierarchy of
/// <paramref name="serviceClosureType" />
/// </summary>
/// <param name="componentContext">the component context used for resolution</param>
/// <param name="serviceClosureType">the service closure type</param>
/// <param name="openGenericType">the open generic type to close</param>
/// <returns>
/// a collection of closed <see cref="openGenericType" /> on the type hierarchy of
/// <paramref name="serviceClosureType" />
/// </returns>
public static IEnumerable<object> ResolveManyClosedGenericsOfTypeHierarchy(this IComponentContext componentContext,
Type serviceClosureType,
Type openGenericType)
{
return ResolveManyClosedGenericsOfTypeHierarchy(componentContext.Resolve, serviceClosureType, openGenericType);
}
/// <summary>
/// Resolve closed generics of <paramref name="openGenericType" /> based on the type hierarchy of
/// <paramref name="serviceClosureType" />
/// </summary>
/// <param name="container">the container used for resolution</param>
/// <param name="serviceClosureType">the service closure type</param>
/// <param name="openGenericType">the open generic type to close</param>
/// <returns>
/// a collection of closed <see cref="openGenericType" /> on the type hierarchy of
/// <paramref name="serviceClosureType" />
/// </returns>
public static IEnumerable<object> ResolveManyClosedGenericsOfTypeHierarchy(this IContainer container,
Type serviceClosureType,
Type openGenericType)
{
return ResolveManyClosedGenericsOfTypeHierarchy(container.Resolve, serviceClosureType, openGenericType);
}
/// <summary>
/// Resolve closed generics of <paramref name="openGenericType" /> based on the type hierarchy of
/// <paramref name="serviceClosureType" />
/// </summary>
/// <param name="resolver">
/// a resolution <see cref="Func{TInput, TResult}" /> that resolves <see cref="Type" /> input into
/// an <see cref="object" />
/// </param>
/// <param name="serviceClosureType">the service closure type</param>
/// <param name="openGenericType">the open generic type to close</param>
/// <returns>
/// a collection of closed <see cref="openGenericType" /> on the type hierarchy of
/// <paramref name="serviceClosureType" />
/// </returns>
public static IEnumerable<object> ResolveManyClosedGenericsOfTypeHierarchy(Func<Type, object> resolver,
Type serviceClosureType,
Type openGenericType)
{
if (resolver == null)
{
throw new ArgumentNullException(nameof(resolver));
}
if (serviceClosureType == null)
{
throw new ArgumentNullException(nameof(serviceClosureType));
}
if (openGenericType == null)
{
throw new ArgumentNullException(nameof(openGenericType));
}
if (!openGenericType.IsGenericTypeDefinition)
{
throw new ArgumentException("type must be a generic type definition", nameof(openGenericType));
}
var typesToResolve = GetAllClosedGenericOfTypeHierarchy(serviceClosureType, openGenericType);
return _()
.SelectMany(o => o);
IEnumerable<IEnumerable<object>> _()
{
foreach (var type in typesToResolve)
{
yield return (IEnumerable<object>) resolver(type);
}
}
}
/// <summary>
/// Create a closed generic type of <see cref="openGenericType" /> for each <see cref="type" /> and its implementing
/// <see langwod="interface" /> and base class
/// </summary>
/// <param name="type">the type to find linage of</param>
/// <param name="openGenericType">the open generic to make closed types of</param>
/// <returns>a collection of closed generic types</returns>
private static IEnumerable<Type> GetAllClosedGenericOfTypeHierarchy(Type type,
Type openGenericType)
{
return _();
IEnumerable<Type> _()
{
foreach (var selfAndSuper in GetSelfAndSupers(type))
{
var closedFeederType = openGenericType.MakeGenericType(selfAndSuper);
yield return typeof(IEnumerable<>).MakeGenericType(closedFeederType);
}
}
}
/// <summary>
/// Given a <see cref="Type" /> <paramref name="inputType" /> return a collection of <paramref name="inputType" />, all
/// of <paramref name="inputType" />'s interfaces, and all of its base classes
/// </summary>
/// <param name="inputType">the type to determine linage of</param>
/// <returns>
/// a collection of type including <paramref name="inputType" />, all of its interfaces, and all of its base
/// classes
/// </returns>
private static IEnumerable<Type> GetSelfAndSupers(Type inputType)
{
return _()
.Distinct();
IEnumerable<Type> _()
{
// return self
yield return inputType;
// return interfaces
foreach (var t in inputType.GetInterfaces())
{
yield return t;
}
// return base types
var baseType = inputType.BaseType;
while (baseType != null)
{
yield return baseType;
baseType = baseType.BaseType;
}
}
}
}
Am I jumping though hoops I shouldn't be to make this happen?
Just for consistency sake, this is the approach I'm taking for DTO validation, where animals are various types of DTOs and the "feeders" are explicit units of DTO validation.
Currently, I am working on IEGL10 in Xamarin. I have implemented ISurfaceHolderCallback and on SurfaceCreated(ISurfaceHolder holder) I have to call a method like this.
public void SurfaceCreated(ISurfaceHolder holder)
{
mEglSurface = mEgl.EglCreateWindowSurface(mEglDisplay, mEglConfig,
holder, null);
}
The problem is, the holder is a C# interface and EglCreateWindowSurface requires Java.Lang.Object. So how can I do the casting. If I directly cast holder like (Java.Lang.Object)holder. It is throwing invalid cast exception.
Please help guys I am really stuck here.
How to cast C# interface to Java.Lang.Object?
MonoDroid has integrated extension for this purpose :
Java.Lang.Object holder_object = holder.JavaCast<Java.Lang.Object>();
EGLSurface mEglSurface = mEgl.EglCreateWindowSurface(mEglDisplay, mEglConfig, holder_object, null);
You could see the document :
public static class Extensions
{
//
// Summary:
// /// Performs an Android runtime-checked type conversion. ///
//
// Parameters:
// instance:
// /// An Android.Runtime.IJavaObject instance to convert /// to a TResult instance.
// ///
//
// Type parameters:
// TResult:
// /// The type to convert instance to. /// TResult must implement the /// Android.Runtime.IJavaObject
// interface. ///
//
// Returns:
// /// A TResult representation for /// instance. ///
//
// Exceptions:
// T:System.ArgumentException:
// ///
// /// The JNI class for TResult cannot be found. ///
// ///
// -or-
// ///
// /// The proxy class for TResult is /// abstract, and the non-abstract Proxy can't
// be found. ///
// ///
//
// T:System.InvalidCastException:
// /// The Anrdroid object instance instance.Handle /// cannot be converted to the
// Android type corresponding to /// TResult. ///
//
// T:System.NotSupportedException:
// /// An unknown error occurred. ///
//
// Remarks:
// /// /// This is a hack, but a currently necessary one. /// ///
// /// Most of the Android types are staticly generated /// wrappers over a description
// of the underlying Android types. This /// intermediate description does not expose
// implementation details, /// which sometimes must be relied upon. ///
// ///
// /// For example, consider the /// Javax.Microedition.Khronos.Egl.EGLContext.EGL
// /// property, which returns an instance of the /// Javax.Microedition.Khronos.Egl.IEGL
// /// interface. This interface is useless, containing no members to /// invoke
// or use. The developer is instead expected to convert this /// instance to an
// interface which contains actual operations, such as /// the Javax.Microedition.Khronos.Egl.IEGL10
// interface. /// Unfortunately, the MonoDroid-generated wrappers do not know this,
// /// nor can they (the EGL10 implementation may be removed in a /// future Android
// version). The result is that if developers attempt /// to cast within managed
// code, the result will be a /// System.InvalidCastException: ///
// /// EGL10 egl10 = (EGL10) EGLContext.EGL; // throws ///
// /// The JavaCast() method allows performing such type conversions /// while bypassing
// the managed type system and instead relying upon /// the Android runtime system
// to perform the type checking. This /// allows: ///
// /// EGL10 egl10 = EGLContext.EGL.JavaCast<EGL10>(); // good ///
public static TResult JavaCast<TResult>(this IJavaObject instance) where TResult : class, IJavaObject;
}
I have the following code w/comments: (It does compile)
/// <summary>
/// return a passing result of a particular type
/// </summary>
/// <typeparam name="T">Type of the value to be returned</typeparam>
/// <param name="value">the value to be returned</param>
/// <returns>a passing result</returns>
public static Result<T> Pass(T value)
{
return new Result<T>()
{
Passed = true,
Value = value
};
}
I get the following warning with it:
Warning 1 SA1620 : CSharp.Documentation :
The typeparam tags in the documentation header must
match the generic types for the method.
I did look at the help page for this error, which gives this explanation:
To fix a violation of this rule, add and fill-in one tag
for each generic type parameter on the element, and make sure that
the tags appear in the same order as the element’s type
parameters.
And it has provided sample code:
/// <summary>
/// A sample generic class.
/// </summary>
/// <typeparam name="S">The first generic type parameter.</typeparam>
/// <typeparam name="T">The second generic type parameter.</typeparam>
public class Class1<S, T>
{
}
I don't see anything about mine that breaks the standards it is showing, and I have tried various odd things, but I have no real idea of what I'm supposed to do here.
The only way that this can compile is if this method is inside a class that is generic in T. This method doesn't have any type parameters. If it was generic, there would be type parameters after the name of the method:
public static Result<T> Pass<T>(T value)
{
return new Result<T>()
{
Passed = true,
Value = value
};
}
But that's not the case with your method. So it must be:
class SomeClass<T>
{
public static Result<T> Pass(T value)
{
return new Result<T>()
{
Passed = true,
Value = value
};
}
}
And any documentation about the type parameter belongs up at the class level. E.g.:
/// <summary>
/// This is a result class
/// </summary>
/// <typeparam name="T">Type of the value to be returned</typeparam>
public class Result<T>
{
public bool Passed { get; set; }
public T Value { get; set; }
/// <summary>
/// return a passing result of a particular type
/// </summary>
/// <param name="value">the value to be returned</param>
/// <returns>a passing result</returns>
public static Result<T> Pass(T value)
{
return new Result<T>()
{
Passed = true,
Value = value
};
}
}
A classes Type metadata can be obtained in several ways. Two of them are:
var typeInfo = Type.GetType("MyClass")
and
var typeInfo = typeof(MyClass)
The advantage of the second way is that typos will be caught by the compiler, and the IDE can understand what I'm talking about (allowing features like refactoring to work without silently breaking the code)
Does there exist an equivalent way of strongly referencing members/properties/methods for metadata and reflection? Can I replace:
var propertyInfo = typeof(MyClass).GetProperty("MyProperty")
with something like:
var propertyInfo = property(MyClass.MyProperty)
No, unfortunately not. It's been discussed and even named: infoof (pronounced "in-foof" for comedy value) but it's not been implemented... yet. Eric Lippert has a blog post about it.
The closest you can come in C# 3 is to make the compiler generate an expression tree, and then pull it out of that - but that's hardly pleasant.
I've just implemented an equivalent of constructions 'propertyof' 'methodof' 'fieldof' using Syste.Linq.Expressions
so instead of writing
var mi = typeof (string).GetMethod("Concat", new[] {typeof (object), typeof (object)});
you can use:
var mi = ReflectionHelper.MethodOf(() => string.Concat(new object(), new object()));
Why do we need this? because now we safe to refactor method, we use via reflection
listing of helper class (you may need to add some informative exceptions in methods):
/// <summary>
/// Represents a set of helpers for .net reflection
/// </summary>
public static class ReflectionHelper
{
#region Public methods
/// <summary>
/// Gets a MethodInfo object from specified expression
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="methodExpression"></param>
/// <returns></returns>
public static MethodInfo MethodOf<TResult>(Expression<Func<TResult>> methodExpression)
{
return ((MethodCallExpression)methodExpression.Body).Method;
}
/// <summary>
/// Gets a MethodInfo object from specified expression
/// </summary>
/// <param name="methodExpression"></param>
/// <returns></returns>
public static MethodInfo MethodOf(Expression<Action> methodExpression)
{
return ((MethodCallExpression)methodExpression.Body).Method;
}
/// <summary>
/// Gets a MethodInfo object from specified expression
/// </summary>
/// <param name="methodExpression"></param>
/// <returns></returns>
public static MethodInfo MethodOf<TInstance, TResult>(Expression<Func<TInstance, TResult>> methodExpression)
{
return ((MethodCallExpression)methodExpression.Body).Method;
}
/// <summary>
/// Gets a MethodInfo object from specified expression
/// </summary>
/// <param name="methodExpression"></param>
/// <returns></returns>
public static MethodInfo MethodOf<TInstance>(Expression<Action<TInstance>> methodExpression)
{
return ((MethodCallExpression)methodExpression.Body).Method;
}
/// <summary>
/// Gets a PropertyInfo object from specified expression
/// </summary>
/// <param name="propertyGetExpression"></param>
/// <returns></returns>
public static PropertyInfo PropertyOf<TProperty>(Expression<Func<TProperty>> propertyGetExpression)
{
return ((MemberExpression)propertyGetExpression.Body).Member as PropertyInfo;
}
/// <summary>
/// Gets a PropertyInfo object from specified expression
/// </summary>
/// <param name="propertyGetExpression"></param>
/// <returns></returns>
public static PropertyInfo PropertyOf<TInstance, TProperty>(Expression<Func<TInstance, TProperty>> propertyGetExpression)
{
return ((MemberExpression)propertyGetExpression.Body).Member as PropertyInfo;
}
/// <summary>
/// Gets a FieldInfo object from specified expression
/// </summary>
/// <param name="fieldAccessExpression"></param>
/// <returns></returns>
public static FieldInfo FieldsOf<TProperty>(Expression<Func<TProperty>> fieldAccessExpression)
{
return ((MemberExpression)fieldAccessExpression.Body).Member as FieldInfo;
}
//TODO: ConstructorOf(...)
#endregion //Public methods
}
as I understand we could not use same aproach to getParameterInfo or EventInfo
Another approach to do that, described by Jb Evain, see: http://evain.net/blog/articles/2010/05/05/parameterof-propertyof-methodof?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+jbevain+%28Jb+in+a+nutshell%29
In c# 6 there's still no infoof but there is nameof:
var propertyInfo = typeof(MyClass).GetProperty(nameof(MyClass.MyProperty))
It's certainly not more terse, but at least it's refactoring friendly.
No, there is no such syntax in c#.