Why in a child class, i can not call the extention method defined for the derived class by calling the base class directly ( i get a compile error that the base class does not contain a definition for the extention method).
But instead, i can call the extention method without any compile errors when i call it directly from the child intance.
Below is the code for my question :
using System;
using System.Reflection;
public class Program
{
public static void Main()
{
Child child = new Child();
child.TestMethod();
}
}
// Derived class
public class Mother
{
}
// Child class
public class Child : Mother
{
public Child() : base()
{
}
public void TestMethod()
{
this.ExtentionMethod(3);// Ok: no compile errors
base.ExtentionMethod(3);// Ko: Compilation error (line 27, col 8): 'Mother' does not contain a definition for 'ExtentionMethod'
}
}
public static class Extender
{
public static void ExtentionMethod(this Mother mother, int i)
{
Console.WriteLine($"Mother extention method {i}");
}
}
When you call an extension method, the compiler looks at the type of the reference on the left and finds the most appropriate method. So when you call this.ExtentionMethod, the type of this is used to find the best method.
So in your case, the compiler will look for an extension with a Child first parameter. Since there is not one, it will then find the one with a Mother first parameter (since a Child "is-a" Mother).
Using base does not do a cast - it is used to access members of the base class. Since extension methods are not "members", base does not do what you expect it to do.
An alternative might be to cast this to the base class instead:
((Mother)this).ExtentionMethod(3);
Although I would note that you don't have a different extension method for the derived class, so with what you posted there would be no difference between this.ExtensionMethod and ((Mother)this).ExtensionBethod. The same method (with the same input values) are going to be called.
This an extension to D Stanley's answer.
If you had extension methods on both Mother, and Child, like this:
public static class Extender
{
public static void ExtentionMethod(this Mother mother, int i)
{
Console.WriteLine($"Mother extention method {i}");
}
public static void ExtentionMethod(this Child child, int i)
{
Console.WriteLine($"Child extention method {i}");
}
}
Then there is a distinction between calling it from the sub-class vs the base-class.
From inside Child
this.ExtentionMethod(3);
Will call the Child version.
((Mother)this).ExtentionMethod(3);
Will call the Mother version.
public void TestMethod()
{
this.ExtentionMethod(3);
((Mother)this).ExtentionMethod(3);
}
Would produce the following output with both extension methods from above:
child extention method 3
Mother extention method 3
The other answers offer very good explanations why you have problems, I'd like to make sure you know the fastest way out of that mess:
public void TestMethod()
{
this.ExtentionMethod(3);
Extender.ExtentionMethod((Mother)this, 3);
}
If your compiler does not recognize the extension method, just remove that syntactical sugar. You can still call it just like a regular, public static method and pass the parameters just as if the this keyword for exension methods never existed. It's not either or, you can still go the old way.
Related
Within my projects I often want to have a method (or function if you prefer) that is private, however I also want to access it from ONE other class. Is this a possibility?
To clarify, this method can be accessed from ClassA, its own class but not any other.
There are plenty of ways to do this untill your last statement that is "and ONLY that class", i can only think of 1 way to do that and it is to have the classes laid out in assemblies as such as such:
Assembly A only contains class A with the method you want declared as internal
Assembly B declared as a friendly assembly : https://msdn.microsoft.com/en-us/library/0tke9fxk.aspx and contains code to call A (it can as to it it is internal as if in the same assembly as it is a friend assembly)
No other assembly linked to A , B or both will be able to call the method on class A as it is internal.
The best way that I can think of is this.
In C# 5, a set of caller information attributes were added, namely [System.Runtime.CompilerServices.CallerMemberName], [System.Runtime.CompilerServices.CallerFilePath], and [System.Runtime.CompilerServices.CallerLineNumber]. We can use the CallerFilePathAttribute to see whether the caller comes from a particular .cs file.
Usually, one file will only contain one class or struct. For example, ClassA is defined in ClassA.cs. You can check if the caller file name matches ClassA.cs in the method.
So modify your method's parameters like this:
([CallerFilePath] string callerFilePath = "" /*Other parameters*/)
In the method, check if the callerFilePath matches the file path of ClassA. If it does not, throw an exception saying that the method can only be accessed from ClassA!
You can make this method protected, if it suits your OOP structure:
public class A
{
protected void Test()
{
Console.WriteLine("I can only be called from B");
}
}
public class B : A
{
public void Pub()
{
Test();
}
}
And there many other ways to do this.
However, in general, it sounds like a wrong look at access modifiers.
If you want to only call your method from exactly one place, then just call it from exactly one place.
The fact that this method should be called from another class, makes him public, logically and architecturally.
Another simple way to control member access is using delegates.
Let's assume you have a private method:
class SecureMethod {
private void DoSomething() { }
}
You can provide access to this method by injecting delegate to this method:
class ClassA {
public ClassA(Action secureMethod) { }
}
SecureMethod objWithSecureMethod;
var a = new ClassA( objWithSecureMethod.DoSomething );
I'm showing you how do to this, but these are very bad practices:
public class A
{
private void CanOnlyCallMethodInClassB();
public static void SetHandlerCanOnlyCallMethodInClassB(ClassB b)
{
b.MethodFromClassA = CanOnlyCallMethodInClassB;
}
}
public class B
{
public Action MethodFromClassA { get; set; }
}
in code:
var b = new B();
A.SetHandlerCanOnlyCallMethodInClassB(b);
b.MethodFromClassA();
but better way is to use object of ClassB in method's classA. Search google for strategy pattern or use inheritance.
Whatever you are asking is not possible in C#. I mean you can not allow only one class to use private method. All you can do is to use internal which allows classes of just one assembly to access your methods or protected which is accessible within its class and by derived class instances!
Apart from that There is not any thumb rule for what you are asking but you can do some hack as shown below:
MethodInfo privateMethod = instance.GetType().GetMethod("NameOfPrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
privateMethod.Invoke(instance, new object[] { methodParameters });
One slightly dirty trick to use a method from class B in class A is to make the method protected rather than private and derive A from B.
Another possibility, probably better, is to make the method internal rather than private and then put class A and B in the same assembly.
All of the examples for extension methods that I have seen consume the extension method in a class like:
class Program
{
static void Main()
{
...Call extension method here
}
}
These seem to work because the consuming class is static. Is there a way to consume an extension method in a non static class like below? I can't seem to find any examples like this.
I have my Extension Method class:
using System;
using System.Collections.Generic;
namespace AwesomeApp
{
public static class LinqExtensionMethods
{
public static IEnumerable<T> FindItemsBeforeAndAfter<T>(this IEnumerable<T> items, Predicate<T> matchFilling)
{
if (items == null)
throw new ArgumentNullException("items");
if (matchFilling == null)
throw new ArgumentNullException("matchFilling");
return items;
}
}
}
And I have my class that consumes the extention method
namespace AwesomeApp
{
public class Leaders : ILeaders
{
var leaders = GetAllLeaders();
var orderedleaders = leaders.OrderByDescending(o => o.PointsEarned);
var test = orderedleaders.FindItemsBeforeAndAfter(w => w.UserId == 1);
}
}
If I call the extension method from a static class I do not the the 'Extension method must be defined in a non-generic static class' error:
public class test
{
public void testfunc()
{
List<int> testlist = new List<int>() {1,2,3,4,5,6,7,8,9};
testlist.FindItemsBeforeAndAfter<int>(e => e == 5);
}
}
I have read through all the stackoverflow answers I can find on the non-generic static class error and they deal with writing your extension method but don't deal with consuming it.
So the question is: If using an extension method with a non-static class is not possible then is there any way to do something that works in a similar way? for example it can be called as .ExtensionMethod not Helper.ExtensionMethod(passedObject)??
Resolution: I thought I cut and pasted the extension method from public class Leaders : ILeaders to its own class so that I could make it static but I actually just copied it. The compiler error was pointing to the class name so I did not see the extension method still at the bottom of the file. The error message is accurate and everyone that answered is correct.
These seem to work because the consuming class is static.
No, that's incorrect. Extension methods definitely don't have to be consumed from static classes or static methods.
However, they do have to be declared in a class which is:
Non-nested
Non-generic
Static
You appear to be confusing calling with declaring - when you say:
If I call the extension method from a static class I do not the the 'Extension method must be defined in a non-generic static class' error
... you'll only get that if you try to declare the method in a class which doesn't satisfy all the above criteria. You should double click on the error to show where it's being generated - I'm sure you'll find it's the declaration, not the use of the method.
Note that your final example (class test) is not a static class, nor a static method.
I get the following compilation error at the class name.
Extension method must be defined in a non-generic static class
I am not using normal class. What could be the reason for this. I don't know and don't want to use extension methods.
As requested, here is my comment as an answer:
Without your code there isn't much we can do. My best guess is that you accidentally typed "this" somewhere in a parameter list.
Sample for extension method
public static class ExtensionMethods {
public static object ToAnOtherObject(this object obj) {
// Your operation here
}
}
I had the same problem, and solved it as follows. My code was something like this:
public static class ExtensionMethods
{
public static object ToAnOtherObject(this object obj)
{
// Your operation here
}
}
and I changed it to
public static class ExtensionMethods
{
public static object ToAnOtherObject(object obj)
{
// Your operation here
}
}
I removed the word "this" of the parameter of the method.
I'm guessing this relates to your previous list question; if so, the example I provided is an extension method, and would be:
public static class LinkedListUtils { // name doesn't matter, but must be
// static and non-generic
public static IEnumerable<T> Reverse<T>(this LinkedList<T> list) {...}
}
This utility class does not need to be the same as the consuming class, but extension methods is how it is possible to use as list.Reverse()
If you don't want it as an extension method, you can just make it a local static method - just take away the "this" from the firstparameter:
public static IEnumerable<T> Reverse<T>(LinkedList<T> list) {...}
and use as:
foreach(var val in Reverse(list)) {...}
The following points need to be considered when creating an extension method:
The class which defines an extension method must be non-generic and static
Every extension method must be a static method
The first parameter of the extension method should use the this keyword.
How about posting your code? Extension methods are declared by preceding the first parameter of a static method with this. Since you don't won't to use an extension method, I suspect you accidentally started a parameter list with this.
Look for something like:
void Method(this SomeType name)
{
}
This is a contrived example:
public static class MyExtensions
{
public static void MyMethod( this MyInterface obj, string txt )
{
}
}
interface MyInterface {}
public MyDerived : MyInterface
{
void DoStuff()
{
MyMethod( "test" ); // fails; compiler can't find MyMethod?
}
}
In my example above, I'm trying to call an extension method assigned to an interface from my derived class. The compiler fails here and says that MyMethod does not exist in the current context. I have all the appropriate using statements in my CS file, so I'm not sure what is going on.
Try invoking it like this:
this.MyMethod("test");
Here is alternate solution (preferred by me):
(this as MyInterface).MyMethod("test");
Why? - because the solution provided previously will not work in cases when extension method calls class's "new" method (property is a method too). In such cases you may intend to call an extension method on the type declared by the base class/interface, which might behave differently from the derived class/interface.
Also, this solution will work for both "new" and "override" methods, because virtual "override" will anyway invoke derived version, which would be also intended.
EDIT: this may be irrelevant if you don't really want to pass "base" to the extension method and instead allow it take "this". However, you must consider behavioral differences.
Also, interesting to note as an answer to the comment by Darin Dimitrov: extension methods don't require instance to run them, because they are static methods. You can invoke an extension method as static by passing parameters to it. However, "base" is not a valid parameter value for parameter marked with "this" in the extension method declaration, which (if I were MS), would allow to simplify general usage of extension methods.
Try calling it this way instead:
this.MyMethod("test");
Change the call to
this.MyMethod("test")
This code compiles:
public static class MyExtensions
{
public static void MyMethod( this MyInterface obj, string txt )
{
}
}
public interface MyInterface {}
public class MyDerived : MyInterface
{
void DoStuff()
{
this.MyMethod( "test" ); // works now
}
}
In a non-static method I could use this.GetType() and it would return the Type. How can I get the same Type in a static method? Of course, I can't just write typeof(ThisTypeName) because ThisTypeName is known only in runtime. Thanks!
If you're looking for a 1 liner that is equivalent to this.GetType() for static methods, try the following.
Type t = MethodBase.GetCurrentMethod().DeclaringType
Although this is likely much more expensive than just using typeof(TheTypeName).
There's something that the other answers haven't quite clarified, and which is relevant to your idea of the type only being available at execution time.
If you use a derived type to execute a static member, the real type name is omitted in the binary. So for example, compile this code:
UnicodeEncoding.GetEncoding(0);
Now use ildasm on it... you'll see that the call is emitted like this:
IL_0002: call class [mscorlib]System.Text.Encoding
[mscorlib]System.Text.Encoding::GetEncoding(int32)
The compiler has resolved the call to Encoding.GetEncoding - there's no trace of UnicodeEncoding left. That makes your idea of "the current type" nonsensical, I'm afraid.
Another solution is to use a selfreferecing type
//My base class
//I add a type to my base class use that in the
//static method to check the type of the caller.
public class Parent<TSelfReferenceType>
{
public static Type GetType()
{
return typeof(TSelfReferenceType);
}
}
Then in the class that inherits it, I make a self referencing type:
public class Child: Parent<Child>
{
}
Now the call type typeof(TSelfReferenceType) inside Parent will get and return the Type of the caller without the need of an instance.
Child.GetType();
You can't use this in a static method, so that's not possible directly. However, if you need the type of some object, just call GetType on it and make the this instance a parameter that you have to pass, e.g.:
public class Car {
public static void Drive(Car c) {
Console.WriteLine("Driving a {0}", c.GetType());
}
}
This seems like a poor design, though. Are you sure that you really need to get the type of the instance itself inside of its own static method? That seems a little bizarre. Why not just use an instance method?
public class Car {
public void Drive() { // Remove parameter; doesn't need to be static.
Console.WriteLine("Driving a {0}", this.GetType());
}
}
I don't understand why you cannot use typeof(ThisTypeName). If this is a non-generic type, then this should work:
class Foo {
static void Method1 () {
Type t = typeof (Foo); // Can just hard code this
}
}
If it's a generic type, then:
class Foo<T> {
static void Method1 () {
Type t = typeof (Foo<T>);
}
}
Am I missing something obvious here?
When your member is static, you will always know what type it is part of at runtime. In this case:
class A
{
public static int GetInt(){}
}
class B : A {}
You cannot call (edit: apparently, you can, see comment below, but you would still be calling into A):
B.GetInt();
because the member is static, it does not play part in inheritance scenarios. Ergo, you always know that the type is A.
For my purposes, I like #T-moty's idea. Even though I have used "self-referencing type" information for years, referencing the base class is harder to do later.
For example (using #Rob Leclerc example from above):
public class ChildA: Parent<ChildA>
{
}
public class ChildB: Parent<ChildB>
{
}
Working with this pattern can be challenging, for example; how do you return the base class from a function call?
public Parent<???> GetParent() {}
Or when type casting?
var c = (Parent<???>) GetSomeParent();
So, I try to avoid it when I can, and use it when I must. If you must, I would suggest that you follow this pattern:
class BaseClass
{
// All non-derived class methods goes here...
// For example:
public int Id { get; private set; }
public string Name { get; private set; }
public void Run() {}
}
class BaseClass<TSelfReferenceType> : BaseClass
{
// All derived class methods goes here...
// For example:
public TSelfReferenceType Foo() {}
public void Bar(TSelfRefenceType obj) {}
}
Now you can (more) easily work with the BaseClass. However, there are times, like my current situation, where exposing the derived class, from within the base class, isn't needed and using #M-moty's suggestion just might be the right approach.
However, using #M-moty's code only works as long as the base class doesn't contain any instance constructors in the call stack. Unfortunately my base classes do use instance constructors.
Therefore, here's my extension method that take into account base class 'instance' constructors:
public static class TypeExtensions
{
public static Type GetDrivedType(this Type type, int maxSearchDepth = 10)
{
if (maxSearchDepth < 0)
throw new ArgumentOutOfRangeException(nameof(maxSearchDepth), "Must be greater than 0.");
const int skipFrames = 2; // Skip the call to self, skip the call to the static Ctor.
var stack = new StackTrace();
var maxCount = Math.Min(maxSearchDepth + skipFrames + 1, stack.FrameCount);
var frame = skipFrames;
// Skip all the base class 'instance' ctor calls.
//
while (frame < maxCount)
{
var method = stack.GetFrame(frame).GetMethod();
var declaringType = method.DeclaringType;
if (type.IsAssignableFrom(declaringType))
return declaringType;
frame++;
}
return null;
}
}
EDIT
This methods will works only when you deploy PDB files with the executable/library, as markmnl pointed out to me.
Otherwise will be a huge issue to be detected: works well in developement, but maybe not in production.
Utility method, simply call the method when you need, from every place of your code:
public static Type GetType()
{
var stack = new System.Diagnostics.StackTrace();
if (stack.FrameCount < 2)
return null;
return (stack.GetFrame(1).GetMethod() as System.Reflection.MethodInfo).DeclaringType;
}