The problem is that you are comparing different languages and trying to force square pegs into round holes.
For Java AspectJ fills a need due to limits in the language, but .NET doesn't necessarily have these limitations, as the JVM doesn't, but Java does.
For example, you can use IronPython or IronRuby (in addition to others) to write assemblies that are very dynamic, so you can write a DSL (domain specific language) that will enable a user to add in code that is not XML, but will change how the program operates.
You can use extension methods in C# to change the behavior by swapping out assemblies, so you have an assembly that have extensions that log to a file, then you swap that assembly for another one with the same namespace that will send the data to a webservice, or do a noop.
But, there are limitations to this that may be hard to overcome, such as being able to use one aspect to do something in every function called, such as using cflow (http://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html), but that may be because I haven't thought enough about how to do it.
My point is not to give a complete explanation of how .NET doesn't need AspectJ, but to show that there are ways to get the behavior you may expect without using AOP.
For apps running on the JVM you can use Groovy, Clojure, JRuby and Scala, for example, to work around the limitations of Java.
UPDATE:
I was hoping to keep my answer shorter, but some understanding of AOP may be useful to add context to my answer.
Aspect Oriented Programming (AOP) is a different programming paradigm, for functionality that cuts across classes, such as logging. Logging is a common situation, where you may want to log all SQL queries being used, so, rather than copying code from place to place, you put it in one place and it gets put into everywhere you specify, so, if you decide later to change where the logging goes, you change it in one place.
But with AspectJ there are more options. For example, you sell a program that stores passwords. Company A uses IDEA, company B uses AES. In order to adapt you change the code that is used at runtime so you don't have to risk recompiling the code and introducing new bugs, and it is changed, so that whenever someone calls getPassword()
the new code is used to decrypt it.
You can also add functionality to an existing class, so I would put methods into interfaces so that everything that used that interface now had access to the functions, so the methods were now concrete, in the interface.
But, by using other languages that are on the .NET and JVM you can do all of these, with the same modularity, by carefully picking which language to use. For example, in Java you can access classes written in Groovy or Scala, so you can get more flexibility with these languages and still have the main app in Java.
In C# you can use F#, IronPython or IronRuby, for example, to get this functionality, or, for some cases you can use C#.
So the need for aspect oriented programming is lessened due to these dynamic, or strongly-typed functional languages, being available on these virtual machines, but, you trade the complexity of working with aspects with having a multi-language solution.
For more on AOP, IBM had some incredible articles about using it, with their AOP@Work series: http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=AOP@work:
For some thoughts on AOP on .NET you can read Code mangling AOP vs. Runtime Proxy AOP
, http://rogeralsing.com/2008/01/08/code-mangling-aop-vs-runtime-proxy-aop/