0

The topic I'm currently in is code sharing. It is suggested that using the access modifier internal for sharing code between multiple files is possible. But is it? Or do I got it wrong? I can't post the link, because the source is not accessible for everyone.

Is it possible to have the definition of a class in one file (like an interface, or abstract class) and have the implementation of it in another file (and using internal here)?

Here is some pseudo code (obviously not working). Definition in one file:

internal static class SongLoader
{
    internal async static Task<IEnumerable<Song>> Load();
    internal async static Task<Stream> OpenData();
}

Implementation in another file:

internal static class SongLoader
{
    internal const string Filename = "songs.json";

    internal static async Task<IEnumerable<Song>> Load()
    {
        // implementation
    }

    internal static Stream OpenData()
    {
        // implemenation
    }
}

Or is it possible to have Load() defined in one file and OpenData() in another, while using internal access modifier? Is this possible? How?

grabner
  • 1,219
  • 3
  • 13
  • 23
  • within files in the same assembly : https://msdn.microsoft.com/en-us/library/7c5ka91b.aspx –  Jun 30 '16 at 11:31
  • @Stanley: Yeah, it should be in the same assembly because it gets compiled into the same project (see [Shared Projects](https://developer.xamarin.com/guides/cross-platform/application_fundamentals/shared_projects/)). – grabner Jun 30 '16 at 11:36
  • 1
    `internal` is just a visibility modifier. It has nothing to do with splitting up a class into multiple files. The keyword for that is `partial`. But there is no such thing as a "definition of a class" you are describing. The closest thing are "partial methods", but they must return `void` and they are always private methods. – Dennis_E Jun 30 '16 at 11:38
  • @Dennis_E: On the website I mentioned it is stated that *`partial` is sort of variant on class mirroring (use of `internal`)* ... I also believe that for my example only `partial` is possible. – grabner Jun 30 '16 at 12:07

4 Answers4

4

internal is an access modifier that deals with what code can access your functions. What you are looking for is the partial keyword if you want to break up a class into several files within the same namespace.

https://msdn.microsoft.com/en-us/library/wa80x488.aspx

partial will not let you define the same function definition twice; you'll need to override or virtualize, or work with a base class if that's what you're aiming for. Partial is handy at times, but it can lead to a somewhat cluttered solution if you're not sure what class can be found where.

MartijnK
  • 642
  • 5
  • 19
  • 1
    You cannot define the same function twice with partial classes either, which I think is what the OP wants – Camilo Terevinto Jun 30 '16 at 11:37
  • You're right, if he's looking for the same function definition twice, that won't work. You'd have to override a base function if that's the route you're looking for. I've added that comment to my answer, just to be safe. – MartijnK Jun 30 '16 at 11:40
2

internal specifier is used to restrict the class/members being used in other than the containing assembly.

Code sharing is achieved via partial classes. You can have part of a class in one file and the other part in another file.

In File A

public partial class MyClass
{
  public void Foo()
  {
  }
}

In File B

public partial class MyClass
{
  public void Bar()
  {
  }
}

You cannot have declaration in one file and definition in one file as in C++. If you have such requirements, you should think about interface or abstract classes.

  • In my case hiding a member between different assemblies would be helpful. So I could have different implementations, but also use the same "contract". About the split of declaration and definition: This was only an example how to reach code sharing somehow. In my concrete example `Foo()` is calling `Bar()`, but there are different variants of `Bar()` depending on the assembly. – grabner Jun 30 '16 at 12:07
  • You cannot basically have same function implemented specifically for different assemblies. If you tell more about the problem you have, then we can discuss about alternate solutions. –  Jun 30 '16 at 13:09
  • I want to gain some knowledge in code sharing options. `internal` was mentioned as one of the options (besides `partial`). So `internal` seems not helping with code sharing. Now I tried to use `partial` as you suggested, but I don't see the full benefit here. If you are interested you can look into my tries [here](https://codeshare.io/dDOXz). – grabner Jun 30 '16 at 13:42
  • You have marked `OpenData()` as `virtual` in a partial class and you are trying to define `OpenData()` in other part of the partial class. In fact when compiling all members will be within the same class regardless of files. So now there are two methods with ambiguous name & signature. And you are also calling non-static method `OpenData()` from a static method `Load()`. If you want to have multiple implementation of `OpenData()`, implement them in different classes with same interface and consume that in `Load()` method. –  Jul 01 '16 at 17:31
1

Access modifiers only deal with who can see the code, not how it is implemented.
The closest way to do what you want is by using abstract classes.

As an example:

internal abstract class SongLoader //under SongLoader.cs
{
    internal async virtual Task<IEnumerable<Song>> Load();
    internal async virtual Task<Stream> OpenData();
}

internal sealed class SongLoaderImplementer : SongLoader //under SongLoaderImplementer.cs
{
    internal override async Task<IEnumerable<Song> Load() {}
    internal override async Task<Stream> OpenData() {}
}
Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
0

Sorry, I know it is too late, but still I'd like to give an answer. It seems your question comes from "Xamarin university", so:

Or is it possible to have Load() defined in one file and OpenData() in another, while using internal access modifier? Is this possible? How?

Yes. You should take out OpenData() method outside and implement it in each platform-specific project. You don't need to have this method in "Shared project". Like following:

Android project:

internal class SongLoaderManager
{
    internal static Stream OpenData(string fileName)
    {
        return Android.App.Application.Context.Assets.Open(fileName);
    }
}

IOS project:

internal class SongLoaderManager
{
    internal static Stream OpenData(string fileName)
    {
        return System.IO.File.OpenRead(fileName);
    }
}

Shared project:

public static partial class SongLoader
{
    const string Filename = "songs.json";

    public static async Task<IEnumerable<Song>> Load()
    {
        using (var reader = new StreamReader(SongLoaderManager.OpenData(Filename))) 
        {
            return JsonConvert.DeserializeObject<List<Song>>(await reader.ReadToEndAsync());
        }
    }

    // NOT NEEDED ANYMORE
    //public static Stream OpenData()
    //{
    //    // TODO: add code to open file here.
    //    return null;
    //}

}

In each plaform you can define their own OpenData() method with different behaviours.

maskalek
  • 453
  • 5
  • 18