PC&웹/VS프로그래밍
C#, Object 값 형식을 보관하는 일반화된 클래스
Simulz™
2022. 11. 8. 16:48
반응형
DevExpress의 컨트롤을 사용하면 값을 읽고 쓸 수 있는 EditValue 항목이 있다.
그런데 Object 형식이다 보니, 다른 곳에 값을 전달할 때 형변환을 해야하는 귀차니즘이 있다.
DataRow Column 값도 마찬가지.
그래서 자동으로 형변환을 해주는 클래스를 만들었다. 처음에는 변수 선언을 해야 하니 반자동...
(개인용이므로 참고만 할 것)
코드
using System;
using System.Collections.Generic;
using System.Data;
namespace Data
{
/*
* Update: 2023-05-18
*/
/// <summary>
/// 레코드의 데이터와 컬럼 정보를 포함합니다.
/// </summary>
/// <typeparam name="T">데이터 형식</typeparam>
public record Value<T> : IComparable<Value<T>>
{
public Value(string name)
{
Name = name;
}
/// <summary>
/// 컬럼명. Column Name
/// </summary>
public string Name { get; private set; }
/// <summary>
/// 파라미터 이름을 가져옵니다. Parameter Name
/// </summary>
public string ParamName { get => $"@{Name}"; }
/// <summary>
/// 데이터 값. for TypedValue
/// </summary>
protected T fEditValue;
/// <summary>
/// 객체 형식의 값을 저장하거나 가져옵니다. Object Value
/// </summary>
public virtual object EditValue
{
get => fEditValue;
set
{
if (value == DBNull.Value)
{
fEditValue = default;
}
else if (CSType.IsGenericType && CSType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (value == null)
{
fEditValue = default(T);
}
else
{
var parseData = value;
if (IsRequireParse)
{
if (CallbackParser is null) throw new NoNullAllowedException("CallbackParser is null");
parseData = CallbackParser(value);
}
fEditValue = (T)Convert.ChangeType(parseData, Nullable.GetUnderlyingType(CSType));
}
}
else
{
var parseData = value;
if (IsRequireParse)
{
if (CallbackParser is null) throw new NoNullAllowedException("CallbackParser is null");
parseData = CallbackParser(value);
}
fEditValue = (T)Convert.ChangeType(parseData, CSType);
}
if (!AllowDBNull && fEditValue == null)
{
if (CSType == typeof(string))
fEditValue = (T)(object)string.Empty;
else if (typeof(T).IsValueType)
throw new NoNullAllowedException("Null 값을 허용하지 않습니다.");
}
}
}
/// <summary>
/// 형식화된 값을 저장하거나 가져옵니다. Typed Value
/// </summary>
public virtual T TypedValue { get => fEditValue; set => fEditValue = value; }
/// <summary>
/// DB 형식의 값을 가져옵니다. DB Typed Value
/// </summary>
public object DbValue { get => (object)fEditValue ?? DBNull.Value; }
/// <summary>
/// 데이터 길이. Data Length
/// </summary>
public int DbSize { get; set; }
/// <summary>
/// C# 데이터 형식을 가져옵니다. C# Type
/// </summary>
public Type CSType { get => typeof(T); }
/// <summary>
/// DB 데이터 형식을 저장하거나 가져옵니다. DB Type
/// </summary>
public DbType DbType { get; set; }
/// <summary>
/// Null 값 허용 여부. Allow DB Nullable
/// </summary>
public bool AllowDBNull { get; set; }
/// <summary>
/// 테이블 형식. DataColumn
/// </summary>
public DataColumn DataColumn { get; set; }
/// <summary>
/// 설명. Description
/// </summary>
public string Description { get; set; }
public bool IsRequireParse { get; set; }
public Func<object, T> CallbackParser { get; set; }
int IComparable<Value<T>>.CompareTo(Value<T> other)
{
if (other == null) throw new ArgumentNullException("other");
if (CSType == other.CSType)
{
if (EqualityComparer<T>.Default.Equals(fEditValue, other.fEditValue))
{
return 0;
}
else
{
return -1;
}
}
else
{
return -1;
}
}
}
}
잡다한게 많은 이유는 DataTable, Database에 사용해야 해서...
사용
클래스 내에서 선언
public Value<decimal> DEC { get; set; }
메소드 내에서 정의
DEC = new("가격") { DbType = DbType.Decimal, EditValue = value };
사용
값을 연산할 때
editDEC.EditValue = Math.Abs(DEC.TypedValue);
DataRow에서 인덱싱할 때
editDEC.EditValue = dataRow[DEC.Name];
개체.TypedValue를 사용하면 형변환된 값을 가져올 수 있다. 위의 예에서는 Math.Abs(decimal 값)이 된다.
DataRow에서 컬럼 인덱싱할 때, 문자열은 리팩터리가 안 되고 인텔리센스가 안 되니 오류 위험이 많은데, 위처럼 개체.Name을 사용하면 알아서 문자열 값을 적용한다.
OleDb, FireDb 등 각 데이터베이스 유형별로 만들어 사용한다. 데이터베이스 유형은 일반화할 필요가 없다.
반응형