Problem
I would like to greatly reduce verbosity of following code fragment.
What I’d like to do:
- Reduce number of occurrences of
MaterialRangedParam<Value>
andMaterialParam<Value>
. C++ has typedef. C# doesn’t. Is there keyword for own type of a class? - Remove
operator !=
,operator ==
,GetHashCode
andEquals
and make compiler generate them for me (the way C++ would do it).
How can I do that?
Additional info:
I’m already aware that clone
method offers functionality similar to ICloneable. I have no need to support ICLoneable at the moment.
Usage pattern:
Those items are going to be stuffed into several lists, arrays and hashtables, compared to each other, assign
is going to be called often.
Advice?
public class MaterialParam<Value> where Value: System.IEquatable<Value>{
public string name = "";
public string shaderValueName = "";
public Value value;// = Value();
public void assignFrom(MaterialParam<Value> other){
name = other.name;
shaderValueName = other.shaderValueName;
value = other.value;
}
public MaterialParam<Value> clone(){
var result = new MaterialParam<Value>();
result.assignFrom(this);
return result;
}
public override bool Equals(object obj){
if(!(obj is MaterialParam<Value>))
return false;
MaterialParam<Value> other = (MaterialParam<Value>)obj;
if((System.Object)other == null){
return false;
}
return (this.name == other.name) &&
(this.shaderValueName == other.shaderValueName) &&
(this.value.Equals(other.value));
}
public override int GetHashCode(){
return name.GetHashCode() ^ shaderValueName.GetHashCode()
^ value.GetHashCode();
}
public static bool operator !=(MaterialParam<Value> a, MaterialParam<Value> b){
return !(a == b);
}
public static bool operator ==(MaterialParam<Value> a, MaterialParam<Value> b){
return a.Equals(b);
}
};
public class MaterialRangedParam<Value>: MaterialParam<Value> where Value: System.IEquatable<Value>{
public Value minValue;// = Value();
public Value maxValue;// = Value();
public void assignFrom(MaterialRangedParam<Value> other){
base.assignFrom(other);
minValue = other.minValue;
maxValue = other.maxValue;
}
new public MaterialRangedParam<Value> clone(){
var result = new MaterialRangedParam<Value>();
result.assignFrom(this);
return result;
}
public override bool Equals(object obj){
if (!base.Equals(obj))
return false;
if(!(obj is MaterialRangedParam<Value>))
return false;
MaterialRangedParam<Value> other = (MaterialRangedParam<Value>)obj;
if((System.Object)other == null){
return false;
}
return (minValue.Equals(other.minValue)) && (maxValue.Equals(other.maxValue));
}
public override int GetHashCode(){
return base.GetHashCode() ^ minValue.GetHashCode() ^ maxValue.GetHashCode();
}
public static bool operator !=(MaterialRangedParam<Value> a, MaterialRangedParam<Value> b){
return !(a == b);
}
public static bool operator ==(MaterialRangedParam<Value> a, MaterialRangedParam<Value> b){
return a.Equals(b);
}
}
Solution
This code looks very Java-like in its style and implementation. Maybe C#1.0 at its best. There are a number of stylistic and idiomatic changes I’d make to make these two classes “play well” in the C# / .NET world of 2015. Without going into exhaustive detail, I employed object immutability, parameterized constructors, implementing IClonaebl
e, utilizing properties, correctly implementing Equals
and ==
.
With regards to the two things that you’d like to do, sorry, neither are possible (nor really desirable) with C# for various reasons that you can find on MSDN.
The code:
public class MaterialParam<TValue> where TValue : IEquatable<TValue>, ICloneable
{
public readonly string name = string.Empty;
public readonly string shaderValueName = string.Empty;
public readonly TValue value; // = Value();
public MaterialParam()
{
}
public MaterialParam(string name, string shaderValueName, TValue value)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (shaderValueName == null)
{
throw new ArgumentNullException("shaderValueName");
}
if (value == null)
{
throw new ArgumentNullException("value");
}
this.name = name;
this.shaderValueName = shaderValueName;
this.value = value;
}
public MaterialParam(MaterialParam<TValue> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
this.name = other.name;
this.shaderValueName = other.shaderValueName;
this.value = other.value;
}
public string Name
{
get
{
return this.name;
}
}
public string ShaderValueName
{
get
{
return this.shaderValueName;
}
}
public TValue Value
{
get
{
return this.value;
}
}
public static bool operator ==(MaterialParam<TValue> a, MaterialParam<TValue> b)
{
if (ReferenceEquals(a, b))
{
return true;
}
if (((object)a == null) || ((object)b == null))
{
return false;
}
return a.Equals(b);
}
public static bool operator !=(MaterialParam<TValue> a, MaterialParam<TValue> b)
{
return !(a == b);
}
public MaterialParam<TValue> Clone()
{
return new MaterialParam<TValue>(this);
}
public override bool Equals(object obj)
{
if (!(obj is MaterialParam<TValue>))
{
return false;
}
var other = (MaterialParam<TValue>)obj;
return (this.name == other.Name)
&& (this.shaderValueName == other.ShaderValueName)
&& this.value.Equals(other.Value);
}
public override int GetHashCode()
{
return this.name.GetHashCode()
^ this.shaderValueName.GetHashCode()
^ this.value.GetHashCode();
}
}
public class MaterialRangedParam<TValue> : MaterialParam<TValue> where TValue : IEquatable<TValue>, ICloneable
{
public readonly TValue minValue; // = Value();
public readonly TValue maxValue; // = Value();
public MaterialRangedParam(TValue minValue, TValue maxValue)
{
if (minValue == null)
{
throw new ArgumentNullException("minValue");
}
if (maxValue == null)
{
throw new ArgumentNullException("maxValue");
}
this.minValue = minValue;
this.maxValue = maxValue;
}
public MaterialRangedParam(MaterialRangedParam<TValue> other) : base(other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
this.minValue = other.MinValue;
this.maxValue = other.MaxValue;
}
public TValue MinValue
{
get
{
return this.minValue;
}
}
public TValue MaxValue
{
get
{
return this.maxValue;
}
}
public static bool operator ==(MaterialRangedParam<TValue> a, MaterialRangedParam<TValue> b)
{
if (ReferenceEquals(a, b))
{
return true;
}
if (((object)a == null) || ((object)b == null))
{
return false;
}
return a.Equals(b);
}
public static bool operator !=(MaterialRangedParam<TValue> a, MaterialRangedParam<TValue> b)
{
return !(a == b);
}
public new MaterialRangedParam<TValue> Clone()
{
return new MaterialRangedParam<TValue>(this);
}
public override bool Equals(object obj)
{
if (!(obj is MaterialRangedParam<TValue>))
{
return false;
}
var other = (MaterialRangedParam<TValue>)obj;
return base.Equals(other) && this.minValue.Equals(other.MinValue) && this.maxValue.Equals(other.MaxValue);
}
public override int GetHashCode()
{
return base.GetHashCode() ^ this.minValue.GetHashCode() ^ this.maxValue.GetHashCode();
}
}