Skip to content

[AI Refactoring] ScreenMirroring.SendGenericMouseEvent IEnumerable 3중 열거 제거 + 예외 타입 오용(empty→ArgumentNullException) 정상화 [Scope: src/Tizen.Multimedia.Remoting] (2026-05-17) #7643

@JoonghyunCho

Description

@JoonghyunCho

[Type: Refactoring]
[Scope: src/Tizen.Multimedia.Remoting]
[Priority: 🟡 Improvement]
[Lens: Performance, Clean Code, Coding Guidelines]

Observation

ScreenMirroring.SendGenericMouseEvent 가 입력 IEnumerable<UibcMouseInfo>3 번 열거 (.Any().Count()foreach) 하고, 빈 입력에 대해 ArgumentNullException 을 던지는 의미상 잘못된 예외 타입 을 사용합니다. UIBC (User Input Back Channel) 는 미러링 세션 중 사용자 마우스 입력 마다 발생할 수 있어 high-frequency 경로입니다.

Before

// src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs:504-557
public void SendGenericMouseEvent(IEnumerable<UibcMouseInfo> uibcMouseInfos, ScreenMirroringMouseEventType type)
{
    ValidateState(ScreenMirroringState.Connected, ScreenMirroringState.Playing);

    if (!uibcMouseInfos.Any())                                  // ← 열거 #1
    {
        throw new ArgumentNullException(nameof(uibcMouseInfos)); // ← 타입 오용 (empty != null)
    }

    var uibcMouseInfosSize = uibcMouseInfos.Count();             // ← 열거 #2
    var uibcMouse = new Native.UibcMouse[uibcMouseInfosSize];
    int i = 0;
    IntPtr unmanagedUibcMousePtr;

    foreach (var uibcMouseInfo in uibcMouseInfos)                // ← 열거 #3
    {
        uibcMouse[i].id = uibcMouseInfo.Id;
        uibcMouse[i].x = uibcMouseInfo.X;
        uibcMouse[i++].y = uibcMouseInfo.Y;
    }
    // ... marshalling 후 Native call
}

Problem

  • 🚀 Performance
    • IEnumerable<T> 가 deferred (e.g. Select, yield-return 시퀀스) 인 경우 3 회 재실행
    • Any() / Count() 는 LINQ 디스패치 + 가능 시 ICollection cast 시도 → 박싱은 없으나 가상 호출 비용
    • null 인풋이면 .Any() 호출에서 NullReferenceException 으로 죽음 (예외 메시지 부정확)
  • 🧹 Clean Code — 동일 시퀀스를 3 번 평가, 변수명 uibcMouseInfosSize 가 한 번만 사용 후 폐기
  • 📐 Coding Guidelines — 빈 컬렉션 → ArgumentException 이 옳고 ArgumentNullExceptionnull 입력 전용. .NET API 가이드라인의 명백한 위반

Proposed Improvement

한 번 materialize 후 인덱스 기반 루프로 변환. 정확한 예외 타입 사용.

After

public void SendGenericMouseEvent(IEnumerable<UibcMouseInfo> uibcMouseInfos, ScreenMirroringMouseEventType type)
{
    ArgumentNullException.ThrowIfNull(uibcMouseInfos);

    ValidateState(ScreenMirroringState.Connected, ScreenMirroringState.Playing);

    // 한 번만 materialize
    var infos = uibcMouseInfos as IReadOnlyList<UibcMouseInfo>
                ?? uibcMouseInfos.ToArray();

    if (infos.Count == 0)
    {
        throw new ArgumentException("uibcMouseInfos cannot be empty.", nameof(uibcMouseInfos));
    }

    var uibcMouse = new Native.UibcMouse[infos.Count];
    for (int i = 0; i < infos.Count; i++)
    {
        var info = infos[i];
        uibcMouse[i].id = info.Id;
        uibcMouse[i].x  = info.X;
        uibcMouse[i].y  = info.Y;
    }
    // ... marshalling 후 Native call (변경 없음)
}

Target Files

  • src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs (L504-L557, 위 발췌 범위만 수정)

Expected Impact (Quantitative Metrics)

  • 시퀀스 열거: 3회 → 1회 (deferred IEnumerable 입력 시 절감 효과 가장 큼)
  • LINQ 호출: Any() + Count() 제거 = 가상 호출 2회 절감
  • null 입력 시 예외 타입: NullReferenceExceptionArgumentNullException (정확성)
  • 빈 입력 시 예외 타입: ArgumentNullExceptionArgumentException (정확성)
  • 잠재적 추가 할당: IReadOnlyList<T> cast 실패 시 .ToArray() 1회 (현재 Count() 도 enumerable cast 시 동일하게 발생할 수 있음 → 순증가 없음)

API Compatibility Check

  • Public API signature change: 없음
  • Behavior change:
    • 정상 입력 (non-null, non-empty): 동일
    • null 입력: 던지는 예외가 NullReferenceExceptionArgumentNullException (의도된 픽스, breaking 으로 보지 않음 — null 가드 강화)
    • 빈 컬렉션: ArgumentNullExceptionArgumentException (의도된 픽스)
  • Tizen API Level floor: 유지 (ArgumentNullException.ThrowIfNull 은 .NET 6+, 본 어셈블리는 이미 그 이상 타겟)

Impact Scope

  • 호출 사이트: 메서드 내부 변경만, 외부 호출자 영향 없음 (public API 시그니처/문서화된 예외 의미 유지)
  • 1 메서드, 약 15 라인 수정
  • public API 문서 (<exception> 태그) 도 함께 갱신 권장

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions