Replies: 25 comments 6 replies
-
propertyof() would be cool too. I could think of a few more. I always felt, that working with reflection, should be as natural to the language, as working with the constructs themselves. |
Beta Was this translation helpful? Give feedback.
-
Did you not read the final sentence of the OP? 😒
Really? Cause I don't. I recall that Reflection deliberately looks different from normal code because that makes it a giant red flag. It's not supposed to be used willy-nilly. Furthermore, reflection over members that are already visible at compile-time seems pretty useless to me. The primary uses of reflection are 1) to obtain info from types that are passed into it from assemblies that depend on you, and 2) to obtain values that are not visible at compile time (e.g. private fields). |
Beta Was this translation helpful? Give feedback.
-
Using reflection primarily along with code-gen, I can see the use for this. I've wasted a fair amount of time trying to find the specific That said, I'd fully acknowledge that this proposal does not come close to meeting the 80/20 rule. |
Beta Was this translation helpful? Give feedback.
-
As an example of a good use case, consider a dependency injection system. Autofac, for example, is based on factory methods. So you register a component via factory method (pseudo code):
Now say you have a class Foo with a static factory method that you want to register:
I could register it like this:
But this can get very verbose and repetitive. In cases like these, I'd prefer to be able to register a MethodInfo and let the DI system do the work of resolving each dependency:
Of course I can do this today, but it is verbose and error prone and I get no help from the compiler. |
Beta Was this translation helpful? Give feedback.
-
So... Does Autofac not support, say |
Beta Was this translation helpful? Give feedback.
-
Previous discussions about this: dotnet/roslyn#1653, dotnet/roslyn#128. Bot of them were closed by LDM members, they didn't think it makes sense to add this feature to the language. |
Beta Was this translation helpful? Give feedback.
-
Related (compiler intrinsics): dotnet/roslyn#11475 (comment) |
Beta Was this translation helpful? Give feedback.
-
Mads backing up what I said about the way reflection is designed. |
Beta Was this translation helpful? Give feedback.
-
I'd somewhat agree, but I do think it's worth having a
|
Beta Was this translation helpful? Give feedback.
-
@HaloFour What is the advantage of this compared to compiler intrinsics? |
Beta Was this translation helpful? Give feedback.
-
I'd have to have to see a proposed function signature. I don't think a compiler intrinsic could produce as neat a syntax as proper language support, but I'd be satisfied if it came close. |
Beta Was this translation helpful? Give feedback.
-
Ok, how about this: MethodInfo methodInfo = ((Action<int>)MyClass.Foo).GetMethodInfo();
A compiler intrinsics call should be something similar probably with better performance. |
Beta Was this translation helpful? Give feedback.
-
So it would manifest as a method that accepts a Such a solution may solve the simple case, same as Update: Fixed references to CoreFX repo issues. |
Beta Was this translation helpful? Give feedback.
-
Yes, Autofac supports that style of recursive dependency resolution. However, in cases where you have multiple constructors, you need to choose between:
Further, if you have a case where a class uses factory methods (I'm not going to go into the details of when and why factory methods are appropriate as that is way too much of a tangent for this thread), then constructor selection heuristics don't help you. If you also are trying to use classes that are not specifically designed to be used in a DI system and you don't want to wrap them to add attributes, then you end up with number 3 from above, which is what I was trying to demonstrate earlier in the thread. In this case, it would be great if the compiler could help me do this (give me language support to select a constructor or factory method that I can pass off to the DI system). |
Beta Was this translation helpful? Give feedback.
-
An equivalent feature has been discussed by the language design team for at least the last decade, known as the "info of" operator, or "infoof, pronounced "in-foof". Its never much got going because of the weight of needing the syntax to describe the signature overloads. |
Beta Was this translation helpful? Give feedback.
-
That is interesting, thanks for the info @mattwar.
Can you expand a bit on this? It seems like the "weight" would be a bit less than the weight of defining signature overloads, and about the same as when calling overloads. That is, if defining a function looks like this:
and calling a function looks like this:
Then describing a function for an infoof operation like this seems very reasonable to me:
Is there more that I'm missing? |
Beta Was this translation helpful? Give feedback.
-
I'm not sure I get this argument, though. Sure, it needs some new syntax, but so do most features. The syntax itself is not that complicated. Identifier followed by parenthesis containing a comma-separated list of types. The only thing that I think complicates it is having to determine if that syntax is valid whether This very syntax should already exist. It should have happened for |
Beta Was this translation helpful? Give feedback.
-
@HaloFour good point on the method rename issue... maybe this feature could gain more traction if the 'overload syntax' was implemented and working with |
Beta Was this translation helpful? Give feedback.
-
I had an idea regarding the syntax of this: Memberof(singlemethod) |
Beta Was this translation helpful? Give feedback.
-
It is a fair argument to make that nameof is nearly all the way to infoof. Maybe with just a little more help. 😁 |
Beta Was this translation helpful? Give feedback.
-
I've tossed a proposal up to argue for overload disambiguation with Would help if I included the link to the proposal: #995 |
Beta Was this translation helpful? Give feedback.
-
I would suggest such syntax:
Also implementation must not use the search by function name using strings or something like, because it won't work after code obfuscation. |
Beta Was this translation helpful? Give feedback.
-
I've included a couple examples of why this would be a useful language feature in dotnet/roslyn#31427 might be useful for the discussion. I have a problem understanding why disambiguation is such an overwhelming issue considering that I've never coded a method call (with intellisense guiding me to the overload I'm trying to target) that actually executed on a different overload at runtime. But then I'm a peabrained code monkey not a language designer. |
Beta Was this translation helpful? Give feedback.
-
This is my little Reflection helper - which (ab)uses lambda functions and expression trees to do the heavy lifting ... using System;
using SR = System.Reflection;
using SLE = System.Linq.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace My.Util {
public static class Info {
public class WrapExpr {
readonly SLE.Expression expr;
public WrapExpr (SLE.Expression E) => expr = E;
public SR.MethodInfo MethodInfo => expr is SLE.MethodCallExpression mce ? mce.Method : null;
public SR.ConstructorInfo ConstructorInfo => expr is SLE.NewExpression ne ? ne.Constructor : null;
public SR.MemberInfo MemberInfo => expr is SLE.MemberExpression me ? me.Member : null;
public SR.PropertyInfo PropertyInfo => MemberInfo is SR.PropertyInfo pi ? pi : null;
public SR.FieldInfo FieldInfo => MemberInfo is SR.FieldInfo fi ? fi : null;
} // class WrapExpr
public static WrapExpr InfoOf<R> (SLE.Expression<Func<R>> lf) => new WrapExpr (lf.Body); // R func ()
public static WrapExpr InfoOf<T1, R> (SLE.Expression<Func<T1, R>> lf) => new WrapExpr (lf.Body); // R func (T1)
public static WrapExpr InfoOf<T1, T2, R> (SLE.Expression<Func<T1, T2, R>> lf) => new WrapExpr (lf.Body); // R func (T1, T2)
public static WrapExpr InfoOf (SLE.Expression<Action> lf) => new WrapExpr (lf.Body); // void func ()
public static WrapExpr InfoOf<T1> (SLE.Expression<Action<T1>> lf) => new WrapExpr (lf.Body); // void func (T1)
public static WrapExpr InfoOf<T1, T2> (SLE.Expression<Action<T1, T2>> lf) => new WrapExpr (lf.Body); // void func (T1, T2)
// 3 and more parameters are left as an exercise to the reader .. ;-P
} // class Info
[TestClass] public class _ReflectionHelp {
public class C {
public C () { }
public int F;
public int P { get; set; }
public void A1 (int i) { }
public int F1 (int i) => i;
} // class C
[TestMethod] public void _Check1 () {
var c = new C ();
var fi = Info.InfoOf (() => c.F).FieldInfo;
var pi = Info.InfoOf (() => c.P).PropertyInfo;
var ci = Info.InfoOf (() => new C ()).ConstructorInfo;
var a1i = Info.InfoOf (() => c.A1 (0)).MethodInfo;
var f1i = Info.InfoOf (() => c.F1 (0)).MethodInfo;
Assert.AreEqual (fi.Name, "F");
Assert.AreEqual (pi.Name, "P");
Assert.AreEqual (ci.Name, ".ctor");
Assert.AreEqual (a1i.Name, "A1");
Assert.AreEqual (f1i.Name, "F1");
} // _Check1
} // class _ReflectionHelp
} // namespace Note, that the body of the lambda function(s) never gets actually called - so its OK to pass bogus arguments to the function calls in the lambda function, as long as the type is correct. |
Beta Was this translation helpful? Give feedback.
-
I agree. infoof wouldn't just be useful for performance, refactoring and ease, but it would also help when dealing with obfuscation. This post will focus mostly on methods.
Currently, you can create a delegate of a method and then invoke the private static void Main()
{
MethodInfo info = new SomeMethodDel<int>(Program.SomeMethod<int>).Method;
info.Invoke(null, new object[] { 1, false, 3.14f });
}
private delegate T SomeMethodDel<T>(int a, bool b, float c);
private static T SomeMethod<T>(int a, bool b, float c)
{
// ...
} This of course is cumbersome, since you have to define a delegate for each method you need to infoof(). Now, I've read the original article by Eric Lippert from 2009 (https://blogs.msdn.microsoft.com/ericlippert/2009/05/21/in-foof-we-trust-a-dialogue), and all his arguments against it are either invalid, or have been ignored when implementing other features, such as delegates. His most compelling argument against it, in my opinion is overload resolution (pretty much all of his other arguments are about their budget). Imagine this code: public class Base<T>
{
public void Bar(int x, int y) { }
public void Bar(T x, int y) { }
}
public class Child : Base<int>
{
public Child()
{
MethodInfo info = infoof(Bar(int, int));
}
} His argument is that this would resolve to
Do I? Because delegates don't, and last I checked delegates ARE in the language. public class Base<T>
{
public void Bar(int x, int y) { }
public void Bar(T x, int y) { }
}
public class Child : Base<int>
{
private delegate void BarFoo(int x, int y);
public Child()
{
BarFoo barFoo = new BarFoo(this.Bar);
}
} That's the exact same scenario but with delegates instead. This is a current feature, and this will also pick the So in the end, for methods at least, it's simply a matter of combining delegate declaration and method retrieval. private static void Main()
{
MethodInfo info = infoof(Program.SomeMethod<int>)
}
private static T SomeMethod<T>(int a, bool b, float c)
{
return default(T);
} Here, there's no ambiguity, so it's as simple as But what if there's only one overload, and someone adds 5 new parameters to it? Now the Sure. Example with overloads. static void Main(string[] args)
{
MethodInfo info = infoof(Program.Bar(int)); // Gets MethodInfo of void Bar(int a)
}
private static void Bar()
{
}
private static void Bar(int a)
{
} How about this, though? static void Main(string[] args)
{
MethodInfo info = infoof(Program.Bar(int));
}
private static void Bar(int a)
{
}
private static void Bar<T>(T a)
{
} This would get the Quote from Eric's article:
How about just making public members a priority, and if there's a public member, private members won't be considered at all, in which case a And instead of Examples: MethodInfo method1 = methodof(MyClass.Bla);
MethodInfo method2 = methodof(MyClass.Bla(int, bool));
MethodInfo method2 = methodof(MyClass.Bla(bool));
MethodInfo method2 = pmethodof(MyClass.Bla(bool));
FieldInfo field1 = fieldof(MyClass.a);
FieldInfo field2 = fieldof(MyClass.b);
FieldInfo field2 = pfieldof(MyClass.c);
MethodInfo indexer1 = indexerof(MyClass[int]);
MethodInfo indexer2 = indexerof(MyClass[string]); Note the lack of
|
Beta Was this translation helpful? Give feedback.
-
C# already supports a
typeof
operator keyword that gets aSystem.Type
for a specified type. However, you get no help from the compiler if you want to do further introspection. For example, once I have theSystem.Type
, if I want to get a method namedFoo
with oneint
parameter, then I have to do something like:And unfortunately if I get this wrong, I won't know until runtime.
It would be much nicer if instead I could do something like:
Using this syntax, members would be have the usual accessibility (e.g. private members would be visible from within a type, public members would be visible outside the type, etc.). Further, we'd have compile time support for this so you'd know right away if you got something wrong, or if the method signature changes after writing your reflection code. Finally, this would work for all member types, and therefore could be used to get FieldInfos, PropertyInfos, MethodInfos, EventInfos, or ConstructorInfos.
Beta Was this translation helpful? Give feedback.
All reactions