Skip to content

Release 0.8.1#14

Merged
CoderGamester merged 1 commit intomasterfrom
develop
Aug 27, 2023
Merged

Release 0.8.1#14
CoderGamester merged 1 commit intomasterfrom
develop

Conversation

@CoderGamester
Copy link
Copy Markdown
Owner

@CoderGamester CoderGamester commented Aug 27, 2023

Add the auto execute process to fill up the version service data based on the git information
Add the possibility to bind multiple interfaces in one call

Summary by CodeRabbit

  • New Feature: Added GitEditorProcess class for running Git commands from within Unity, allowing developers to perform version control operations directly in the editor.
  • New Feature: Added VersionEditorUtils class for managing the internal version of the game, providing a centralized way to handle versioning and updates.
  • New Feature: Enhanced the IInstaller interface and its implementation Installer to support binding multiple interfaces to a single instance, improving flexibility and modularity in dependency injection.
  • Chore: Various code improvements and optimizations to enhance performance and maintainability.

Summary by CodeRabbit

  • New Feature: Added GitEditorProcess class to run Git commands as processes, enabling checks for valid Git repositories, retrieving current branch names, commit hashes, and diffs from given commits.
  • New Feature: Introduced VersionEditorUtils class for managing application versioning. This includes setting and saving the internal version before building, loading version data from disk, and generating an internal version suffix based on Git information and build settings.
  • Refactor: Enhanced IInstaller interface with new methods for binding multiple type interfaces to a single instance, improving modularity and code organization.

Add the auto execute process to fill up the version service data based on the git information
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 27, 2023

Walkthrough

This pull request introduces new classes and methods to enhance the Git process handling and versioning in Unity projects. It also extends the IInstaller interface with methods for binding multiple interfaces to an instance, improving modularity and flexibility.

Changes

File Summary
Editor.meta, Editor/GitEditorProcess.cs.meta, Editor/VersionEditorUtils.cs.meta New metadata files introduced with specific format versions and GUIDs.
Editor/GitEditorProcess.cs New class providing functionality to run Git commands as processes within Unity.
Editor/VersionEditorUtils.cs New static class for managing internal application versioning based on Git information and build settings.
Runtime/Installer.cs Extended IInstaller interface with methods for binding multiple interfaces to a given instance.

🐇💻

Code changes here, code changes there,

Enhancing our project with utmost care.

With Git commands running smooth and fine,

And versioning that's simply divine.

Multiple interfaces bound in a trice,

Oh, isn't this update just so nice! 🎉


Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • Mention @coderabbitai in any review comment for bot assistance. The bot stays silent unless called upon.
  • Note: Review comments are made on code diffs or files, not on the PR overview.

Pause Incremental Reviews

  • Insert @coderabbitai: ignore in the PR description to halt the bot's ongoing reviews. Remove the line to resume.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Aug 27, 2023

Image description CodeRabbit

Walkthrough

The changes include the addition of two new classes: GitEditorProcess for running Git commands within Unity, and VersionEditorUtils for managing the internal version of the game. Additionally, the IInstaller interface and its implementation Installer now support binding multiple interfaces to a single instance.

Changes

File Summary
Editor/GitEditorProcess.cs
Editor/VersionEditorUtils.cs
Added GitEditorProcess class for running Git commands from within Unity and added VersionEditorUtils class for managing the internal version of the game.
Runtime/Installer.cs Added the ability to bind multiple interfaces to a single instance in the IInstaller interface and its implementation Installer.

🐇 "In Unity's realm, Git commands run,
Version managed, all is done.
Bind interfaces, one instance strong,
A rabbit sings a joyful song!" 🎵🐰


Uplevel your code reviews with CodeRabbit Pro

CodeRabbit Pro

If you like this project, please support us by purchasing the Pro version. The Pro version has advanced context, superior noise reduction and several proprietary improvements compared to the open source version.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

Commits Files that changed from the base of the PR and between 6a2518d and 5c0c804 commits.
Files selected (3)
  • Editor/GitEditorProcess.cs (1)
  • Editor/VersionEditorUtils.cs (1)
  • Runtime/Installer.cs (4)
Files ignored due to filter (4)
  • Editor.meta
  • Editor/GitEditorProcess.cs.meta
  • Editor/VersionEditorUtils.cs.meta
  • package.json
Files skipped from review due to trivial changes (1)
  • Runtime/Installer.cs
Review comments generated (15)
  • Review: 14
  • LGTM: 1

Tips

Chat with Image description CodeRabbit Bot (@coderabbitai)

  • Reply on review comments left by this bot to ask follow-up questions. A review comment is a comment on a diff or a file.
  • Invite the bot into a review comment chain by tagging @coderabbitai in a reply.

Code suggestions

  • The bot may make code suggestions, but please review them carefully before committing since the line number ranges may be misaligned.
  • You can edit the comment made by the bot and manually tweak the suggestion if it is slightly off.

Pausing incremental reviews

  • Add @coderabbitai: ignore anywhere in the PR description to pause further reviews from the bot.

Comment on lines +1 to +4
using System;
using System.Diagnostics;

namespace GameLovers.Services.Editor
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The GameLovers.Services.Editor namespace seems to be unrelated to the purpose of this class. Consider moving the GitEditorProcess class to a more appropriate namespace, such as GameLovers.Utils or GameLovers.VersionControl.

Comment on lines +6 to +12
/// <summary>
/// Run git commands processes that would otherwise be used in the terminal.
/// </summary>
/// <author>
/// https://blog.somewhatabstract.com/2015/06/22/getting-information-about-your-git-repository-with-c/
/// </author>
public class GitEditorProcess : IDisposable
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

Consider adding XML documentation comments to provide descriptions for the class and its members.

Comment on lines +14 to +15
private const string DefaultPathToGitBinary = "git";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The DefaultPathToGitBinary constant is not used in the code. If it's intended to be used as a default value for the pathToGitBinary parameter, consider removing it since the default value can be specified directly in the parameter declaration.

Comment on lines +23 to +32
public GitEditorProcess(string workingDir, string pathToGitBinary = DefaultPathToGitBinary)
{
var startInfo = new ProcessStartInfo
{
UseShellExecute = false,
RedirectStandardOutput = true,
FileName = pathToGitBinary,
CreateNoWindow = true,
WorkingDirectory = workingDir
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

Consider using the var keyword for the startInfo variable to improve readability.

34:
Consider using object initializer syntax to initialize the Process field instead of assigning properties individually.

Comment on lines +37 to +44
/// <summary>
/// Is this unity project a git repo?
/// </summary>
public bool IsValidRepo()
{
return ExecuteCommand("rev-parse --is-inside-work-tree") == "true";
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The IsValidRepo method could be simplified by directly returning the result of the ExecuteCommand method call.

Comment on lines +13 to +15
{
private const int ShortenedCommitLength = 8;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The ShortenedCommitLength constant is not used in the code. It can be removed.

- private const int ShortenedCommitLength = 8;

Comment on lines +19 to +31
public static void SetAndSaveInternalVersion(bool isStoreBuild)
{
var newVersionData = GenerateInternalVersionSuffix(isStoreBuild);
var newVersionDataSerialized = JsonUtility.ToJson(newVersionData);
var oldVersionDataSerialized = LoadVersionDataSerializedSync();
if (newVersionDataSerialized.Equals(oldVersionDataSerialized, StringComparison.Ordinal))
{
return;
}

Debug.Log($"Saving new version data: {newVersionDataSerialized}");
SaveVersionData(newVersionDataSerialized);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The SetAndSaveInternalVersion method has a long and complex implementation. Consider refactoring it to improve readability and maintainability. Here are some suggestions:

  1. Extract the logic for generating the new version data into a separate method.
  2. Move the comparison of old and new version data to a separate method.
  3. Use early returns instead of nested if statements to simplify the control flow.

Here's an example of how the refactored method could look like:

public static void SetAndSaveInternalVersion(bool isStoreBuild)
{
    var newVersionData = GenerateInternalVersionSuffix(isStoreBuild);
    var newVersionDataSerialized = JsonUtility.ToJson(newVersionData);
    var oldVersionDataSerialized = LoadVersionDataSerializedSync();

    if (IsVersionDataEqual(newVersionDataSerialized, oldVersionDataSerialized))
    {
        return;
    }

    Debug.Log($"Saving new version data: {newVersionDataSerialized}");
    SaveVersionData(newVersionDataSerialized);
}

private static bool IsVersionDataEqual(string versionData1, string versionData2)
{
    return versionData1.Equals(versionData2, StringComparison.Ordinal);
}

Comment on lines +36 to +47
public static string LoadVersionDataSerializedSync()
{
var textAsset = Resources.Load<TextAsset>(VersionServices.VersionDataFilename);
if (!textAsset)
{
Debug.LogError("Could not load internal version from Resources.");
return string.Empty;
}

var serialized = textAsset.text;
Resources.UnloadAsset(textAsset);
return serialized;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The LoadVersionDataSerializedSync method loads the game version from a text asset in the Resources folder. However, it does not handle exceptions that may occur during the loading process. Consider adding proper error handling and logging in case the loading fails.

Here's an example of how the method could be modified:

public static string LoadVersionDataSerializedSync()
{
    try
    {
        var textAsset = Resources.Load<TextAsset>(VersionServices.VersionDataFilename);
        if (textAsset != null)
        {
            var serialized = textAsset.text;
            Resources.UnloadAsset(textAsset);
            return serialized;
        }
    }
    catch (Exception e)
    {
        Debug.LogException(e);
    }

    Debug.LogError("Could not load internal version from Resources.");
    return string.Empty;
}

Comment on lines +59 to +99
private static VersionServices.VersionData GenerateInternalVersionSuffix(bool isStoreBuild)
{
var data = new VersionServices.VersionData();

using (var repo = new GitEditorProcess(Application.dataPath))
{
try
{
if (!repo.IsValidRepo())
{
Debug.LogWarning("Project is not a git repo. Internal version not set.");
}
else
{
var branch = repo.GetBranch();
if (string.IsNullOrEmpty(branch))
{
Debug.LogWarning("Could not get git branch for internal version");
}
else
{
data.BranchName = branch;
}

var commitHash = repo.GetCommitHash();
if (string.IsNullOrEmpty(commitHash))
{
Debug.LogWarning("Could not get git commit for internal version");
}
else
{
data.Commit = commitHash.Substring(0, ShortenedCommitLength);
}
}
}
catch (Exception e)
{
Debug.LogException(e);
Debug.LogWarning("Could not execute git commands. Internal version not set.");
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The GenerateInternalVersionSuffix method has a long and complex implementation. Consider refactoring it to improve readability and maintainability. Here are some suggestions:

  1. Extract the logic for retrieving git branch and commit into separate methods.
  2. Use early returns instead of nested if statements to simplify the control flow.

Here's an example of how the refactored method could look like:

private static VersionServices.VersionData GenerateInternalVersionSuffix(bool isStoreBuild)
{
    var data = new VersionServices.VersionData();

    using (var repo = new GitEditorProcess(Application.dataPath))
    {
        try
        {
            if (!repo.IsValidRepo())
            {
                Debug.LogWarning("Project is not a git repo. Internal version not set.");
                return data;
            }

            var branch = GetGitBranch(repo);
            if (string.IsNullOrEmpty(branch))
            {
                Debug.LogWarning("Could not get git branch for internal version");
            }
            else
            {
                data.BranchName = branch;
            }

            var commitHash = GetGitCommitHash(repo);
            if (string.IsNullOrEmpty(commitHash))
            {
                Debug.LogWarning("Could not get git commit for internal version");
            }
            else
            {
                data.Commit = commitHash.Substring(0, 8);
            }
        }
        catch (Exception e)
        {
            Debug.LogException(e);
            Debug.LogWarning("Could not execute git commands. Internal version not set.");
        }
    }

    data.BuildNumber = PlayerSettings.iOS.buildNumber;
    data.BuildType = isStoreBuild ? "prod" : "dev";

    return data;
}

private static string GetGitBranch(GitEditorProcess repo)
{
    return repo.GetBranch();
}

private static string GetGitCommitHash(GitEditorProcess repo)
{
    return repo.GetCommitHash();
}

Comment on lines +101 to +139
data.BuildNumber = PlayerSettings.iOS.buildNumber;
data.BuildType = isStoreBuild ? "prod" : "dev";

return data;
}

/// <summary>
/// Set the internal version of this application and save it in resources. This should be
/// called at edit/build time.
/// </summary>
private static void SaveVersionData(string serializedData)
{
const string assets = "Assets";
const string resources = "Build/Resources";

var absDirPath = Path.Combine(Application.dataPath, resources);
if (!Directory.Exists(absDirPath))
{
Directory.CreateDirectory(absDirPath);
}

// delete old file with incorrect extension
const string assetExtension = ".asset";
var absFilePath = Path.Combine(absDirPath, VersionServices.VersionDataFilename);
if (File.Exists(Path.ChangeExtension(absFilePath, assetExtension)))
{
AssetDatabase.DeleteAsset(
Path.Combine(assets, resources,
Path.ChangeExtension(VersionServices.VersionDataFilename, assetExtension)));
}

// create new text file
const string textExtension = ".txt";
File.WriteAllText(Path.ChangeExtension(absFilePath, textExtension), serializedData);

AssetDatabase.ImportAsset(
Path.Combine(assets, resources,
Path.ChangeExtension(VersionServices.VersionDataFilename, textExtension)));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The SaveVersionData method has a long and complex implementation. Consider refactoring it to improve readability and maintainability. Here are some suggestions:

  1. Use Path.Combine to concatenate file paths instead of manual string concatenation.
  2. Use File.WriteAllText to simplify writing the serialized data to a text file.
  3. Use AssetDatabase.ImportAsset to import the newly created text file into the project.

Here's an example of how the refactored method could look like:

private static void SaveVersionData(string serializedData)
{
    const string assets = "Assets";
    const string resources = "Build/Resources";
    const string versionDataFilename = VersionServices.VersionDataFilename;

    var absDirPath = Path.Combine(Application.dataPath, resources);
    if (!Directory.Exists(absDirPath))
    {
        Directory.CreateDirectory(absDirPath);
    }

    // Delete old file with incorrect extension
    const string assetExtension = ".asset";
    var absFilePath = Path.Combine(absDirPath, versionDataFilename);
    if (File.Exists(Path.ChangeExtension(absFilePath, assetExtension)))
    {
        AssetDatabase.DeleteAsset(Path.Combine(assets, resources, Path.ChangeExtension(versionDataFilename, assetExtension)));
    }

    // Create new text file
    const string textExtension = ".txt";
    File.WriteAllText(Path.ChangeExtension(absFilePath, textExtension), serializedData);

    AssetDatabase.ImportAsset(Path.Combine(assets, resources, Path.ChangeExtension(versionDataFilename, textExtension)));
}

@CoderGamester CoderGamester merged commit 6c14efd into master Aug 27, 2023
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 15

Details

Commits Files that changed from the base of the PR and between 6a2518d and 5c0c804 commits.
Files ignored due to filter (1)
  • package.json
Files selected for processing (6)
  • Editor.meta (1 hunks)
  • Editor/GitEditorProcess.cs (1 hunks)
  • Editor/GitEditorProcess.cs.meta (1 hunks)
  • Editor/VersionEditorUtils.cs (1 hunks)
  • Editor/VersionEditorUtils.cs.meta (1 hunks)
  • Runtime/Installer.cs (4 hunks)
Files skipped from review due to trivial changes (3)
  • Editor.meta
  • Editor/GitEditorProcess.cs.meta
  • Editor/VersionEditorUtils.cs.meta

{
private const string DefaultPathToGitBinary = "git";

private readonly Process Process;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Process field is not encapsulated properly. It's a good practice to make fields private and provide public properties or methods for accessing them if necessary. This helps in maintaining the integrity of the data by preventing external code from changing it unexpectedly.

- private readonly Process Process;
+ private readonly Process _process;

Comment on lines +23 to +35
public GitEditorProcess(string workingDir, string pathToGitBinary = DefaultPathToGitBinary)
{
var startInfo = new ProcessStartInfo
{
UseShellExecute = false,
RedirectStandardOutput = true,
FileName = pathToGitBinary,
CreateNoWindow = true,
WorkingDirectory = workingDir
};

Process = new Process { StartInfo = startInfo };
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructor of GitEditorProcess creates a new Process object but does not start it. If an exception occurs during the creation of the Process object, it might lead to resource leaks as the Dispose method will not be called. Consider using a factory method to create the Process object and handle any exceptions that might occur during its creation.

Comment on lines +81 to +85
Process.StartInfo.Arguments = args;
Process.Start();
var output = Process.StandardOutput.ReadToEnd().Trim();
Process.WaitForExit();
return output;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ExecuteCommand method starts a process, reads its output, and waits for it to exit. However, it does not check whether the process has exited successfully or not. If the process exits with a non-zero status code, this could indicate an error. Consider checking the exit code of the process and handling any errors appropriately.

- Process.Start();
- var output = Process.StandardOutput.ReadToEnd().Trim();
- Process.WaitForExit();
+ _process.StartInfo.Arguments = args;
+ _process.Start();
+ var output = _process.StandardOutput.ReadToEnd().Trim();
+ _process.WaitForExit();
+ if (_process.ExitCode != 0)
+ {
+     throw new InvalidOperationException($"Git command '{args}' failed with exit code {_process.ExitCode}");
+ }

Comment on lines +19 to +31
public static void SetAndSaveInternalVersion(bool isStoreBuild)
{
var newVersionData = GenerateInternalVersionSuffix(isStoreBuild);
var newVersionDataSerialized = JsonUtility.ToJson(newVersionData);
var oldVersionDataSerialized = LoadVersionDataSerializedSync();
if (newVersionDataSerialized.Equals(oldVersionDataSerialized, StringComparison.Ordinal))
{
return;
}

Debug.Log($"Saving new version data: {newVersionDataSerialized}");
SaveVersionData(newVersionDataSerialized);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method SetAndSaveInternalVersion generates a new version data and compares it with the old one. If they are equal, it returns without saving the new version data. This could lead to situations where the version data is not updated even though other changes have been made in the codebase. Consider always saving the new version data regardless of whether it matches the old one.

- if (newVersionDataSerialized.Equals(oldVersionDataSerialized, StringComparison.Ordinal))
- {
-     return;
- }

Comment on lines +36 to +48
public static string LoadVersionDataSerializedSync()
{
var textAsset = Resources.Load<TextAsset>(VersionServices.VersionDataFilename);
if (!textAsset)
{
Debug.LogError("Could not load internal version from Resources.");
return string.Empty;
}

var serialized = textAsset.text;
Resources.UnloadAsset(textAsset);
return serialized;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method LoadVersionDataSerializedSync loads the game version saved on disk into string format. However, there's no error handling for when the file does not exist or cannot be read. Consider adding appropriate error handling to ensure that the application can recover gracefully from such scenarios.

Comment thread Runtime/Installer.cs
/// Thrown if the given <paramref name="instance"/> doesn't implement all type interface
/// </exception>
/// <returns>
/// This installer reference to allow chain calls if necessayr
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a typo in the comment. It should be "necessary" instead of "necessayr".

- /// This installer reference to allow chain calls if necessayr
+ /// This installer reference to allow chain calls if necessary

Comment thread Runtime/Installer.cs

if (!type2.IsInterface)
{
throw new ArgumentException($"Cannot bind {instance} because {type1} is not an interface");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message is incorrect, it should refer to type2 instead of type1.

- throw new ArgumentException($"Cannot bind {instance} because {type1} is not an interface");
+ throw new ArgumentException($"Cannot bind {instance} because {type2} is not an interface");

Comment thread Runtime/Installer.cs

if (!type2.IsInterface)
{
throw new ArgumentException($"Cannot bind {instance} because {type2} is not an interface");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message is incorrect, it should refer to type2 instead of type1.

- throw new ArgumentException($"Cannot bind {instance} because {type1} is not an interface");
+ throw new ArgumentException($"Cannot bind {instance} because {type2} is not an interface");

Comment thread Runtime/Installer.cs

if (!type2.IsInterface)
{
throw new ArgumentException($"Cannot bind {instance} because {type2} is not an interface");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message is incorrect, it should refer to type2 instead of type1.

- throw new ArgumentException($"Cannot bind {instance} because {type1} is not an interface");
+ throw new ArgumentException($"Cannot bind {instance} because {type2} is not an interface");

Comment thread Runtime/Installer.cs
Comment on lines +162 to 196
/// <inheritdoc />
public IInstaller Bind<T1, T2, T3, T4>(T1 instance) where T1 : class, T2, T3, T4
{
var type1 = typeof(T1);
var type2 = typeof(T2);
var type3 = typeof(T3);
var type4 = typeof(T4);

if (!type1.IsInterface)
{
throw new ArgumentException($"Cannot bind {instance} because {type1} is not an interface");
}

if (!type2.IsInterface)
{
throw new ArgumentException($"Cannot bind {instance} because {type2} is not an interface");
}

if (!type3.IsInterface)
{
throw new ArgumentException($"Cannot bind {instance} because {type3} is not an interface");
}

if (!type4.IsInterface)
{
throw new ArgumentException($"Cannot bind {instance} because {type4} is not an interface");
}

_bindings.Add(type1, instance);
_bindings.Add(type2, instance);
_bindings.Add(type3, instance);
_bindings.Add(type4, instance);

return this;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code for checking whether the types are interfaces and adding them to the bindings is repeated multiple times. Consider creating a private method that performs these operations to adhere to the DRY principle.

+ private void BindType<T>(T instance) where T : class
+ {
+     var type = typeof(T);
+
+     if (!type.IsInterface)
+     {
+         throw new ArgumentException($"Cannot bind {instance} because {type} is not an interface");
+     }
+
+     _bindings.Add(type, instance);
+ }

- public IInstaller Bind<T1, T2>(T1 instance) where T1 : class, T2
- {
-     var type1 = typeof(T1);
-     var type2 = typeof(T2);
-
-     if (!type1.IsInterface)
-     {
-         throw new ArgumentException($"Cannot bind {instance} because {type1} is not an interface");
-     }
-
-     if (!type2.IsInterface)
-     {
-         throw new ArgumentException($"Cannot bind {instance} because {type1} is not an interface");
-     }
-
-     _bindings.Add(type1, instance);
-     _bindings.Add(type2, instance);
-
-     return this;
- }
+ public IInstaller Bind<T1, T2>(T1 instance) where T1 : class, T2
+ {
+     BindType<T1>(instance);
+     BindType<T2>(instance);
+
+     return this;
+ }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant