Skip to content

Commit

Permalink
docs: di
Browse files Browse the repository at this point in the history
  • Loading branch information
labbbirder committed Oct 12, 2023
1 parent 826c012 commit 67035a1
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 160 deletions.
4 changes: 3 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
VSProj~
.github
.github
README.md
Documentation
125 changes: 125 additions & 0 deletions Documentation/usage-decorator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# 装饰器

值得一提的是,装饰器的实现有以下优势:

* 调用是0GC,低开销的
* 实现只需要指定一个`DecoratorAttribute`
* 支持装饰异步函数

## 例子

下面的例子实现目标方法执行前和后打印信息

定义一个装饰器,需要继承自`DecoratorAttribute`,并实现`Decorate`方法

```csharp
public class DebugInvocationAttribute:DecoratorAttribute
{
string info;

public DebugInvocationAttribute(string _info)
{
info = _info;
}

void OnCompleted()
{
Debug.Log("end "+info);
}

protected override R Decorate<R>(InvocationInfo<R> invocation)
{
Debug.Log("begin "+info+string.Join(",",invocation.Arguments));
// invoke original method
var r = invocation.FastInvoke();
if(IsAsyncMethod)
{
// delay on async method
invocation.GetAwaiter(r).OnCompleted(OnCompleted);
}
else
{
OnCompleted();
}
return r;
}
}

```

使用

```csharp

public class Demo:MonoBehaviour{

void Start(){
FixHelper.InstallAll();
}

async void Update(){
if(Input.GetKeyDown(KeyCode.A)){
Work(1,"foo");
}
if(Input.GetKeyDown(KeyCode.S)){
await AsyncWork(2,"bar");
print("return");
}
}

//decorate a standard method
[DebugInvocation("w1")]
int Work(int i, string s){
Debug.Log("do work");
return 123+i;
}

//decorate an async method
[DebugInvocation("aw2")]
async Task<int> AsyncWork(int i, string s){
Debug.Log("do a lot work");
await Task.Delay(1000);
return 123+i;
}
}
```

## 异步方法补充说明

async方法有一个值得斟酌的问题。如果上例的Task换成UniTask。则不会打印return,这是因为Decrote方法覆盖了原本的continuationAction(这与UniTask的实现有关)。使用如下Decorate方法可以解决所有此类问题:

```csharp
protected override R Decorate<R>(InvocationInfo<R> invocation)
{
Debug.Log("begin "+info+string.Join(",",invocation.Arguments));
var r = invocation.FastInvoke();
if(IsAsyncMethod)
{
// delay when its an async method
var awaiter = invocation.GetAwaiter(r);
UniTask.Create(async()=>
{
try
{
while(!invocation.IsAwaiterCompleted(awaiter))
await UniTask.Yield();
}
catch {}
finally
{
OnCompleted();
}
});
// invocation.GetAwaiter(r).OnCompleted(OnCompleted);
}
else
{
OnCompleted();
}
return r;
}
```

上例使用`UniTask.Create`创建了一个Timer,可以使用其他类似的方法,如自定义MonoBehaviour等。一旦`IsAwaiterCompleted`检查结束,立即执行自定义的`OnCompleted`方法。

因为Unity没有官方支持的Timer功能,基于“此库只做自己该做的”原则,这里只是给出提示。
142 changes: 142 additions & 0 deletions Documentation/usage-di.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# 依赖注入

依赖注入对于模块间解耦帮助很大。

## 基本用法

在类成员上使用`[SimpleDI]`标签,使其可被注入。

```csharp
public interface IFoo
{

}

public class FooA : IFoo
{

}

public class FooB : IFoo
{

}

public class ServiceA
{
[SimpleDI] public IFoo foo {get;}
}

```

定义规则:

```csharp
void Start()
{
// 使用FooA实现IFoo
ServiceContainer.Bind<IFoo>().AsSingle(noLazy:true).To<FooA>();
}

```

## 支持注入的成员

支持以下成员:

+ 字段、属性
+ 静态成员、实例成员
+ 只读成员、可读可写成员

如:

```csharp
class Foo
{
[SimpleDI] static IFoo foo;
[SimpleDI] static IFoo foo { get; }
[SimpleDI] static IFoo foo { get; set; }
[SimpleDI] IFoo foo;
[SimpleDI] IFoo foo { get; }
[SimpleDI] IFoo foo { get; set; }
}

```

## 更多控制

### 限定DeclaringType

```csharp
void Init()
{
// 使用FooA实现IFoo,只对ServiceA中的成员生效
ServiceContainer.In<ServiceA>().Bind<IFoo>().AsSingle(noLazy:true).To<FooA>();
}

```

### 构造函数

```csharp
interface IFoo { }
class Foo : IFoo
{
public Foo(string name, int age)
{
Console.WriteLine($"我的伙伴{name},{age}岁了");
}
}

void Init()
{
// output: 我的伙伴小黑儿,3岁了
ServiceContainer.Bind<IFoo>().AsSingle(noLazy:true).To<Foo>("小黑儿",3);
}

```

### 生命模式 ScopeMode

+ Single 单例(默认)
+ Transient 每次获取都是新实例

```csharp
// 使用FooA实现IFoo
ServiceContainer.Bind<IManager>().AsSingle().To<FooManager>();
ServiceContainer.Bind<IFoo>().AsTransient().To<Foo>();
```

### 泛型递归

对于`IManager<IFoo,IBar>`会分别查找IManager,IFoo,IBar,并支持泛型约束。

```csharp
interface IFoo
{

}

interface IManager
{

}

class Foo : IFoo
{

}

class Manager : IManager
{

}

```

```csharp
void Init()
{
ServiceContainer.Get<IManager<IFoo>>(); // returns Manager<Foo>
}
```
36 changes: 36 additions & 0 deletions Documentation/usage-proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# 数据代理

下面的代码演示实现一个数据代理:

```csharp
public class Pat : ProxyData // 需要继承ProxyData
{
public string name { get; set; }
public int age { get; set; }
}

var pet = new Pet();
pet.OnSetProperty(key=>{
print($"set {key}");
});
pet.OnGetProperty(key=>{
print($"get {key}");
});

pet.age += 1;

/*
output:
get age
set age
*/

```

有时你需要判断代理类是否被正确注入:

```csharp
print(pet.IsFixed()); // false
FixHelper.InstallAll();
print(pet.IsFixed()); // true
```
Loading

0 comments on commit 67035a1

Please sign in to comment.